From 4c3ba35f07a0fe9bf2a151f6734bdfbe7a4179db Mon Sep 17 00:00:00 2001 From: goaaats Date: Thu, 27 Nov 2025 01:45:13 +0100 Subject: [PATCH 1/5] Don't inhibit ATK close events if pinned or clickthrough windows are focused --- Dalamud/Game/Internal/DalamudAtkTweaks.cs | 4 ++-- Dalamud/Interface/Internal/InterfaceManager.cs | 1 + Dalamud/Interface/Windowing/Window.cs | 10 ++++++++++ Dalamud/Interface/Windowing/WindowSystem.cs | 13 ++++++++++++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Dalamud/Game/Internal/DalamudAtkTweaks.cs b/Dalamud/Game/Internal/DalamudAtkTweaks.cs index 486af463c..466401ef3 100644 --- a/Dalamud/Game/Internal/DalamudAtkTweaks.cs +++ b/Dalamud/Game/Internal/DalamudAtkTweaks.cs @@ -113,7 +113,7 @@ internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService private void AtkUnitBaseReceiveGlobalEventDetour(AtkUnitBase* thisPtr, AtkEventType eventType, int eventParam, AtkEvent* atkEvent, AtkEventData* atkEventData) { // 3 == Close - if (eventType == AtkEventType.InputReceived && WindowSystem.HasAnyWindowSystemFocus && atkEventData != null && *(int*)atkEventData == 3 && this.configuration.IsFocusManagementEnabled) + if (eventType == AtkEventType.InputReceived && WindowSystem.ShouldInhibitAtkCloseEvents && atkEventData != null && *(int*)atkEventData == 3 && this.configuration.IsFocusManagementEnabled) { Log.Verbose($"Cancelling global event SendHotkey command due to WindowSystem {WindowSystem.FocusedWindowSystemNamespace}"); return; @@ -124,7 +124,7 @@ internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService private void AgentHudOpenSystemMenuDetour(AgentHUD* thisPtr, AtkValue* atkValueArgs, uint menuSize) { - if (WindowSystem.HasAnyWindowSystemFocus && this.configuration.IsFocusManagementEnabled) + if (WindowSystem.ShouldInhibitAtkCloseEvents && this.configuration.IsFocusManagementEnabled) { Log.Verbose($"Cancelling OpenSystemMenu due to WindowSystem {WindowSystem.FocusedWindowSystemNamespace}"); return; diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index d68bc8bef..76a1b5172 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -1175,6 +1175,7 @@ internal partial class InterfaceManager : IInternalDisposableService WindowSystem.HasAnyWindowSystemFocus = false; WindowSystem.FocusedWindowSystemNamespace = string.Empty; + WindowSystem.ShouldInhibitAtkCloseEvents = false; if (this.IsDispatchingEvents) { diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs index 44ff62199..f12e87099 100644 --- a/Dalamud/Interface/Windowing/Window.cs +++ b/Dalamud/Interface/Windowing/Window.cs @@ -226,6 +226,16 @@ public abstract class Window /// public bool AllowClickthrough { get; set; } = true; + /// + /// Gets a value indicating whether this window is pinned. + /// + public bool IsPinned => this.internalIsPinned; + + /// + /// Gets a value indicating whether this window is click-through. + /// + public bool IsClickthrough => this.internalIsClickthrough; + /// /// Gets or sets a list of available title bar buttons. /// diff --git a/Dalamud/Interface/Windowing/WindowSystem.cs b/Dalamud/Interface/Windowing/WindowSystem.cs index 87bd199a1..d6e9649bb 100644 --- a/Dalamud/Interface/Windowing/WindowSystem.cs +++ b/Dalamud/Interface/Windowing/WindowSystem.cs @@ -60,6 +60,12 @@ public class WindowSystem /// public string? Namespace { get; set; } + /// + /// Gets or sets a value indicating whether ATK close events should be inhibited while any window has focus. + /// Does not respect windows that are pinned or clickthrough. + /// + internal static bool ShouldInhibitAtkCloseEvents { get; set; } + /// /// Add a window to this . /// The window system doesn't own your window, it just renders it @@ -130,7 +136,7 @@ public class WindowSystem window.DrawInternal(flags, persistence); } - var focusedWindow = this.windows.FirstOrDefault(window => window.IsFocused && window.RespectCloseHotkey); + var focusedWindow = this.windows.FirstOrDefault(window => window.IsFocused); this.HasAnyFocus = focusedWindow != default; if (this.HasAnyFocus) @@ -155,6 +161,11 @@ public class WindowSystem } } + ShouldInhibitAtkCloseEvents |= this.windows.Any(w => w.IsFocused && + w.RespectCloseHotkey && + !w.IsPinned && + !w.IsClickthrough); + if (hasNamespace) ImGui.PopID(); } From d7915c7020f04f15eaa4caa2c341b2356c51a08f Mon Sep 17 00:00:00 2001 From: goaaats Date: Fri, 28 Nov 2025 18:11:31 +0100 Subject: [PATCH 2/5] Show a sensible error message when Lumina fails to init --- Dalamud/Data/DataManager.cs | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/Dalamud/Data/DataManager.cs b/Dalamud/Data/DataManager.cs index d017bf85a..ed0aa6c4d 100644 --- a/Dalamud/Data/DataManager.cs +++ b/Dalamud/Data/DataManager.cs @@ -41,7 +41,7 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager try { Log.Verbose("Starting data load..."); - + using (Timings.Start("Lumina Init")) { var luminaOptions = new LuminaOptions @@ -53,12 +53,25 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager DefaultExcelLanguage = this.Language.ToLumina(), }; - this.GameData = new( - Path.Combine(Path.GetDirectoryName(Environment.ProcessPath)!, "sqpack"), - luminaOptions) + try { - StreamPool = new(), - }; + this.GameData = new( + Path.Combine(Path.GetDirectoryName(Environment.ProcessPath)!, "sqpack"), + luminaOptions) + { + StreamPool = new(), + }; + } + catch (Exception ex) + { + Log.Error(ex, "Lumina GameData init failed"); + Util.Fatal( + "Dalamud could not read required game data files. This likely means your game installation is corrupted or incomplete.\n\n" + + "Please repair your installation by right-clicking the login button in XIVLauncher and choosing \"Repair game files\".", + "Dalamud"); + + return; + } Log.Information("Lumina is ready: {0}", this.GameData.DataPath); @@ -71,7 +84,7 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager dalamud.StartInfo.TroubleshootingPackData); this.HasModifiedGameDataFiles = tsInfo?.IndexIntegrity is LauncherTroubleshootingInfo.IndexIntegrityResult.Failed or LauncherTroubleshootingInfo.IndexIntegrityResult.Exception; - + if (this.HasModifiedGameDataFiles) Log.Verbose("Game data integrity check failed!\n{TsData}", dalamud.StartInfo.TroubleshootingPackData); } @@ -130,7 +143,7 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager #region Lumina Wrappers /// - public ExcelSheet GetExcelSheet(ClientLanguage? language = null, string? name = null) where T : struct, IExcelRow + public ExcelSheet GetExcelSheet(ClientLanguage? language = null, string? name = null) where T : struct, IExcelRow => this.Excel.GetSheet(language?.ToLumina(), name); /// @@ -138,7 +151,7 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager => this.Excel.GetSubrowSheet(language?.ToLumina(), name); /// - public FileResource? GetFile(string path) + public FileResource? GetFile(string path) => this.GetFile(path); /// @@ -161,7 +174,7 @@ internal sealed class DataManager : IInternalDisposableService, IDataManager : Task.FromException(new FileNotFoundException("The file could not be found.")); /// - public bool FileExists(string path) + public bool FileExists(string path) => this.GameData.FileExists(path); #endregion From 78ecb721cd3f48fd06d72b1d850a47ff68f39d1f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 29 Nov 2025 12:47:45 +0000 Subject: [PATCH 3/5] Update ClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 0769d1f18..e5f586630 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 0769d1f180f859688f47a7a99610e9ce10da946c +Subproject commit e5f586630ef06fa48d5dc0d8c0fa679323093c77 From d12a9ec7da4c2e91c22c0d3f848197eb743ba03d Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 29 Nov 2025 19:15:37 +0100 Subject: [PATCH 4/5] Remove DalamudBetaKey, DalamudBetaKind from config Fix all code that depends on it to use Util.GetActiveTrack() instead --- .../Internal/DalamudConfiguration.cs | 10 ---------- Dalamud/Interface/Internal/DalamudInterface.cs | 2 +- .../Internal/Windows/BranchSwitcherWindow.cs | 18 ++++++++---------- .../PluginInstaller/PluginInstallerWindow.cs | 9 ++++----- Dalamud/Support/DalamudReleases.cs | 15 ++++++++++----- Dalamud/Support/Troubleshooting.cs | 2 +- 6 files changed, 24 insertions(+), 32 deletions(-) diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs index da0d7c2c6..9404b5b10 100644 --- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs +++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs @@ -108,11 +108,6 @@ internal sealed class DalamudConfiguration : IInternalDisposableService /// public bool DoPluginTest { get; set; } = false; - /// - /// Gets or sets a key to opt into Dalamud staging builds. - /// - public string? DalamudBetaKey { get; set; } = null; - /// /// Gets or sets a list of custom repos. /// @@ -278,11 +273,6 @@ internal sealed class DalamudConfiguration : IInternalDisposableService /// public bool IsResumeGameAfterPluginLoad { get; set; } = false; - /// - /// Gets or sets the kind of beta to download when matches the server value. - /// - public string? DalamudBetaKind { get; set; } - /// /// Gets or sets a value indicating whether any plugin should be loaded when the game is started. /// It is reset immediately when read. diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index 202334580..64e1acaa4 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -182,7 +182,7 @@ internal class DalamudInterface : IInternalDisposableService () => Service.GetNullable()?.ToggleDevMenu(), VirtualKey.SHIFT); - if (!configuration.DalamudBetaKind.IsNullOrEmpty()) + if (Util.GetActiveTrack() != "release") { titleScreenMenu.AddEntryCore( Loc.Localize("TSMDalamudDevMenu", "Developer Menu"), diff --git a/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs b/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs index 4e95b718e..9cc14ea14 100644 --- a/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs +++ b/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs @@ -6,7 +6,6 @@ using System.Net.Http.Json; using System.Threading.Tasks; using Dalamud.Bindings.ImGui; -using Dalamud.Configuration.Internal; using Dalamud.Interface.Colors; using Dalamud.Interface.Utility; using Dalamud.Interface.Windowing; @@ -15,6 +14,8 @@ using Dalamud.Utility; using Newtonsoft.Json; +using Serilog; + namespace Dalamud.Interface.Internal.Windows; /// @@ -47,7 +48,7 @@ public class BranchSwitcherWindow : Window Debug.Assert(this.branches != null, "this.branches != null"); var trackName = Util.GetActiveTrack(); - this.selectedBranchIndex = this.branches.IndexOf(x => x.Value.Track != trackName); + this.selectedBranchIndex = this.branches.IndexOf(x => x.Value.Track == trackName); if (this.selectedBranchIndex == -1) { this.selectedBranchIndex = 0; @@ -86,12 +87,9 @@ public class BranchSwitcherWindow : Window if (ImGui.Button("Pick & Restart"u8)) { - var config = Service.Get(); - config.DalamudBetaKind = pickedBranch.Key; - config.DalamudBetaKey = pickedBranch.Value.Key; - - // If we exit immediately, we need to write out the new config now - config.ForceSave(); + var newTrackName = pickedBranch.Key; + var newTrackKey = pickedBranch.Value.Key; + Log.Verbose("Switching to branch {Branch} with key {Key}", newTrackName, newTrackKey); var appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var xlPath = Path.Combine(appData, "XIVLauncher", "current", "XIVLauncher.exe"); @@ -104,8 +102,8 @@ public class BranchSwitcherWindow : Window UseShellExecute = false, }; - ps.ArgumentList.Add($"--dalamud-beta-kind={config.DalamudBetaKind}"); - ps.ArgumentList.Add($"--dalamud-beta-key={(config.DalamudBetaKey.IsNullOrEmpty() ? "invalid" : config.DalamudBetaKey)}"); + ps.ArgumentList.Add($"--dalamud-beta-kind={newTrackName}"); + ps.ArgumentList.Add($"--dalamud-beta-key={(newTrackKey.IsNullOrEmpty() ? "invalid" : newTrackKey)}"); Process.Start(ps); Environment.Exit(0); diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index b203b3894..ac092bd25 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -302,8 +302,7 @@ internal class PluginInstallerWindow : Window, IDisposable this.profileManagerWidget.Reset(); - var config = Service.Get(); - if (this.staleDalamudNewVersion == null && !config.DalamudBetaKind.IsNullOrEmpty()) + if (this.staleDalamudNewVersion == null && !Util.GetActiveTrack().IsNullOrEmpty()) { Service.Get().GetVersionForCurrentTrack().ContinueWith(t => { @@ -311,10 +310,10 @@ internal class PluginInstallerWindow : Window, IDisposable return; var versionInfo = t.Result; - if (versionInfo.AssemblyVersion != Util.GetScmVersion() && - versionInfo.Track != "release" && - string.Equals(versionInfo.Key, config.DalamudBetaKey, StringComparison.OrdinalIgnoreCase)) + if (versionInfo.AssemblyVersion != Util.GetScmVersion()) + { this.staleDalamudNewVersion = versionInfo.AssemblyVersion; + } }); } } diff --git a/Dalamud/Support/DalamudReleases.cs b/Dalamud/Support/DalamudReleases.cs index 15e851da2..603c77487 100644 --- a/Dalamud/Support/DalamudReleases.cs +++ b/Dalamud/Support/DalamudReleases.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Dalamud.Configuration.Internal; using Dalamud.Networking.Http; +using Dalamud.Utility; using Newtonsoft.Json; @@ -15,7 +16,7 @@ namespace Dalamud.Support; internal class DalamudReleases : IServiceType { private const string VersionInfoUrl = "https://kamori.goats.dev/Dalamud/Release/VersionInfo?track={0}"; - + private readonly HappyHttpClient httpClient; private readonly DalamudConfiguration config; @@ -30,20 +31,24 @@ internal class DalamudReleases : IServiceType this.httpClient = httpClient; this.config = config; } - + /// /// Get the latest version info for the current track. /// /// The version info for the current track. - public async Task GetVersionForCurrentTrack() + public async Task GetVersionForCurrentTrack() { - var url = string.Format(VersionInfoUrl, [this.config.DalamudBetaKind]); + var currentTrack = Util.GetActiveTrack(); + if (currentTrack.IsNullOrEmpty()) + return null; + + var url = string.Format(VersionInfoUrl, [currentTrack]); var response = await this.httpClient.SharedHttpClient.GetAsync(url); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject(content); } - + [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "laziness")] public class DalamudVersionInfo { diff --git a/Dalamud/Support/Troubleshooting.cs b/Dalamud/Support/Troubleshooting.cs index 4af8d5ffc..88048c462 100644 --- a/Dalamud/Support/Troubleshooting.cs +++ b/Dalamud/Support/Troubleshooting.cs @@ -73,7 +73,7 @@ public static class Troubleshooting DalamudGitHash = Util.GetGitHash() ?? "Unknown", GameVersion = startInfo.GameVersion?.ToString() ?? "Unknown", Language = startInfo.Language.ToString(), - BetaKey = configuration.DalamudBetaKey, + BetaKey = Util.GetActiveTrack(), DoPluginTest = configuration.DoPluginTest, LoadAllApiLevels = pluginManager?.LoadAllApiLevels == true, InterfaceLoaded = interfaceManager?.IsReady ?? false, From 7510c032cc0e706787259b44d4ab2415cc74c8a3 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 29 Nov 2025 19:22:28 +0100 Subject: [PATCH 5/5] Disable Intel CET support, causes CLR crashes on unpatched Windows --- Directory.Build.props | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Directory.Build.props b/Directory.Build.props index 4ed87c809..f9f061c17 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,6 +6,10 @@ x64 x64 13.0 + + + + false