From 8ccfac231830104492d5b53d71c08d36e693f16c Mon Sep 17 00:00:00 2001 From: Soreepeong <3614868+Soreepeong@users.noreply.github.com> Date: Mon, 22 Dec 2025 18:46:29 +0900 Subject: [PATCH 01/99] Fix wrong CancellationToken usage --- Dalamud/Interface/Internal/StaThreadService.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dalamud/Interface/Internal/StaThreadService.cs b/Dalamud/Interface/Internal/StaThreadService.cs index bb5caa281..5e93bbf75 100644 --- a/Dalamud/Interface/Internal/StaThreadService.cs +++ b/Dalamud/Interface/Internal/StaThreadService.cs @@ -113,7 +113,7 @@ internal partial class StaThreadService : IInternalDisposableService using var cts = CancellationTokenSource.CreateLinkedTokenSource( this.cancellationTokenSource.Token, cancellationToken); - await this.taskFactory.StartNew(action, cancellationToken).ConfigureAwait(true); + await this.taskFactory.StartNew(action, cts.Token).ConfigureAwait(true); } /// Runs a given delegate in the messaging thread. @@ -126,7 +126,7 @@ internal partial class StaThreadService : IInternalDisposableService using var cts = CancellationTokenSource.CreateLinkedTokenSource( this.cancellationTokenSource.Token, cancellationToken); - return await this.taskFactory.StartNew(func, cancellationToken).ConfigureAwait(true); + return await this.taskFactory.StartNew(func, cts.Token).ConfigureAwait(true); } /// Runs a given delegate in the messaging thread. @@ -138,7 +138,7 @@ internal partial class StaThreadService : IInternalDisposableService using var cts = CancellationTokenSource.CreateLinkedTokenSource( this.cancellationTokenSource.Token, cancellationToken); - await await this.taskFactory.StartNew(func, cancellationToken).ConfigureAwait(true); + await await this.taskFactory.StartNew(func, cts.Token).ConfigureAwait(true); } /// Runs a given delegate in the messaging thread. @@ -151,7 +151,7 @@ internal partial class StaThreadService : IInternalDisposableService using var cts = CancellationTokenSource.CreateLinkedTokenSource( this.cancellationTokenSource.Token, cancellationToken); - return await await this.taskFactory.StartNew(func, cancellationToken).ConfigureAwait(true); + return await await this.taskFactory.StartNew(func, cts.Token).ConfigureAwait(true); } [LibraryImport("ole32.dll")] From 282fa87571c10b589c7a0b438db5cadb6d9d8533 Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Mon, 22 Dec 2025 19:44:00 +0100 Subject: [PATCH 02/99] Add event for LogMessages being added to the chat --- Dalamud/Game/Chat/LogMessage.cs | 220 ++++++++++++++++++++++++++ Dalamud/Game/Chat/LogMessageEntity.cs | 96 +++++++++++ Dalamud/Game/Gui/ChatGui.cs | 58 +++++++ Dalamud/Plugin/Services/IChatGui.cs | 13 ++ 4 files changed, 387 insertions(+) create mode 100644 Dalamud/Game/Chat/LogMessage.cs create mode 100644 Dalamud/Game/Chat/LogMessageEntity.cs diff --git a/Dalamud/Game/Chat/LogMessage.cs b/Dalamud/Game/Chat/LogMessage.cs new file mode 100644 index 000000000..cf423bd6e --- /dev/null +++ b/Dalamud/Game/Chat/LogMessage.cs @@ -0,0 +1,220 @@ +using Dalamud.Data; +using Dalamud.Game.Text.SeStringHandling; +using Dalamud.Utility; + +using FFXIVClientStructs.FFXIV.Client.System.String; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using FFXIVClientStructs.FFXIV.Client.UI.Misc; +using FFXIVClientStructs.FFXIV.Component.Text; +using FFXIVClientStructs.Interop; + +using Lumina.Excel; + +using System.Diagnostics.CodeAnalysis; + +using TerraFX.Interop.Windows; + +namespace Dalamud.Game.Chat; + +/// +/// Interface representing a log message. +/// +public interface ILogMessage : IEquatable +{ + /// + /// Gets the address of the log message in memory. + /// + nint Address { get; } + + /// + /// Gets the ID of this log message. + /// + uint LogMessageId { get; } + + /// + /// Gets the GameData associated with this log message. + /// + RowRef GameData { get; } + + /// + /// Gets the entity that is the source of this log message, if any. + /// + ILogMessageEntity? SourceEntity { get; } + + /// + /// Gets the entity that is the target of this log message, if any. + /// + ILogMessageEntity? TargetEntity { get; } + + /// + /// Gets the number of parameters. + /// + int ParameterCount { get; } + + /// + /// Retrieves the value of a parameter for the log message if it is an int. + /// + /// The index of the parameter to retrieve. + /// The value of the parameter. + /// if the parameter was retrieved successfully. + bool TryGetIntParameter(int index, out int value); + + /// + /// Retrieves the value of a parameter for the log message if it is a string. + /// + /// The index of the parameter to retrieve. + /// The value of the parameter. + /// if the parameter was retrieved successfully. + bool TryGetStringParameter(int index, [NotNullWhen(true)] out SeString? value); + + /// + /// Formats this log message into an approximation of the string that will eventually be shown in the log. + /// + /// This can cause side effects such as playing sound effects and thus should only be used for debugging. + /// The formatted string. + SeString FormatLogMessageForDebugging(); +} + +/// +/// This struct represents a status effect an actor is afflicted by. +/// +/// A pointer to the Status. +internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessage +{ + /// + public nint Address => (nint)ptr; + + /// + public uint LogMessageId => ptr->LogMessageId; + + /// + public RowRef GameData => LuminaUtils.CreateRef(ptr->LogMessageId); + + public LogMessageEntity SourceEntity => new LogMessageEntity(ptr, true); + /// + ILogMessageEntity? ILogMessage.SourceEntity => ptr->SourceKind == EntityRelationKind.None ? null : this.SourceEntity; + + public LogMessageEntity TargetEntity => new LogMessageEntity(ptr, false); + + /// + ILogMessageEntity? ILogMessage.TargetEntity => ptr->TargetKind == EntityRelationKind.None ? null : this.TargetEntity; + + /// + public int ParameterCount => ptr->Parameters.Count; + + public bool TryGetParameter(int index, out TextParameter value) + { + if (index < 0 || index >= ptr->Parameters.Count) + { + value = default; + return false; + } + + value = ptr->Parameters[index]; + return true; + } + + /// + public bool TryGetIntParameter(int index, out int value) + { + value = 0; + if (!this.TryGetParameter(index, out var parameter)) return false; + if (parameter.Type != TextParameterType.Integer) return false; + value = parameter.IntValue; + return true; + } + + /// + public bool TryGetStringParameter(int index, [NotNullWhen(true)] out SeString? value) + { + value = null; + if (!this.TryGetParameter(index, out var parameter)) return false; + if (parameter.Type == TextParameterType.String) + { + value = SeString.Parse(parameter.StringValue.Value); + return true; + } + if (parameter.Type == TextParameterType.ReferencedUtf8String) + { + value = SeString.Parse(parameter.ReferencedUtf8StringValue->Utf8String.AsSpan()); + return true; + } + + return false; + } + + /// + public SeString FormatLogMessageForDebugging() + { + var logModule = RaptureLogModule.Instance(); + + // the formatting logic is taken from RaptureLogModule_Update + + var utf8 = new Utf8String(); + SetName(logModule, this.SourceEntity); + SetName(logModule, this.TargetEntity); + logModule->RaptureTextModule->FormatString(this.GameData.Value.Text.ToDalamudString().EncodeWithNullTerminator(), &ptr->Parameters, &utf8); + + return SeString.Parse(utf8.AsSpan()); + + void SetName(RaptureLogModule* self, LogMessageEntity item) + { + var name = item.NameSpan.GetPointer(0); + + if (item.IsPlayer) + { + var str = self->TempParseMessage.GetPointer(item.IsSourceEntity ? 8 : 9); + self->FormatPlayerLink(name, str, null, 0, item.Kind != 1 /* LocalPlayer */, item.HomeWorldId, false, null, false); + + if (item.HomeWorldId != 0 && item.HomeWorldId != AgentLobby.Instance()->LobbyData.HomeWorldId) + { + var crossWorldSymbol = self->RaptureTextModule->UnkStrings0.GetPointer(3); + if (!crossWorldSymbol->StringPtr.HasValue) + self->RaptureTextModule->ProcessMacroCode(crossWorldSymbol, "\0"u8); + str->Append(crossWorldSymbol); + if (self->UIModule->GetWorldHelper()->AllWorlds.TryGetValuePointer(item.HomeWorldId, out var world)) + str->ConcatCStr(world->Name); + } + + name = str->StringPtr; + } + + if (item.IsSourceEntity) + { + self->RaptureTextModule->SetGlobalTempEntity1(name, item.Sex, item.ObjStrId); + } + else + { + self->RaptureTextModule->SetGlobalTempEntity2(name, item.Sex, item.ObjStrId); + } + } + } + + + public static bool operator ==(LogMessage x, LogMessage y) => x.Equals(y); + + public static bool operator !=(LogMessage x, LogMessage y) => !(x == y); + + public bool Equals(LogMessage other) + { + return this.LogMessageId == other.LogMessageId && this.SourceEntity == other.SourceEntity && this.TargetEntity == other.TargetEntity; + } + + /// + public bool Equals(ILogMessage? other) + { + return other is LogMessage logMessage && this.Equals(logMessage); + } + + /// + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj is LogMessage logMessage && this.Equals(logMessage); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(this.LogMessageId, this.SourceEntity, this.TargetEntity); + } +} diff --git a/Dalamud/Game/Chat/LogMessageEntity.cs b/Dalamud/Game/Chat/LogMessageEntity.cs new file mode 100644 index 000000000..e4c81c16a --- /dev/null +++ b/Dalamud/Game/Chat/LogMessageEntity.cs @@ -0,0 +1,96 @@ +using System.Diagnostics.CodeAnalysis; + +using Dalamud.Data; +using Dalamud.Game.Text.SeStringHandling; +using Dalamud.Plugin.Services; + +using FFXIVClientStructs.FFXIV.Client.UI.Misc; + +using Lumina.Excel; +using Lumina.Excel.Sheets; + +namespace Dalamud.Game.Chat; + +/// +/// Interface representing an entity related to a log message. +/// +public interface ILogMessageEntity : IEquatable +{ + /// + /// Gets the name of this entity. + /// + SeString Name { get; } + + /// + /// Gets the ID of the homeworld of this entity, if it is a player. + /// + ushort HomeWorldId { get; } + + /// + /// Gets the homeworld of this entity, if it is a player. + /// + RowRef HomeWorld { get; } + + /// + /// Gets the ObjStr ID of this entity, if not a player. See . + /// + uint ObjStrId { get; } + + /// + /// Gets a boolean indicating if this entity is a player. + /// + bool IsPlayer { get; } +} + + +/// +/// This struct represents a status effect an actor is afflicted by. +/// +/// A pointer to the Status. +internal unsafe readonly struct LogMessageEntity(LogMessageQueueItem* ptr, bool source) : ILogMessageEntity +{ + public Span NameSpan => source ? ptr->SourceName : ptr->TargetName; + + public SeString Name => SeString.Parse(this.NameSpan); + + public ushort HomeWorldId => source ? ptr->SourceHomeWorld : ptr->TargetHomeWorld; + + public RowRef HomeWorld => LuminaUtils.CreateRef(this.HomeWorldId); + + public uint ObjStrId => source ? ptr->SourceObjStrId : ptr->TargetObjStrId; + + public byte Kind => source ? (byte)ptr->SourceKind : (byte)ptr->TargetKind; + + public byte Sex => source ? ptr->SourceSex : ptr->TargetSex; + + public bool IsPlayer => source ? ptr->SourceIsPlayer : ptr->TargetIsPlayer; + + public bool IsSourceEntity => source; + + public static bool operator ==(LogMessageEntity x, LogMessageEntity y) => x.Equals(y); + + public static bool operator !=(LogMessageEntity x, LogMessageEntity y) => !(x == y); + + public bool Equals(LogMessageEntity other) + { + return this.Name == other.Name && this.HomeWorldId == other.HomeWorldId && this.ObjStrId == other.ObjStrId && this.Kind == other.Kind && this.Sex == other.Sex && this.IsPlayer == other.IsPlayer; + } + + /// + public bool Equals(ILogMessageEntity other) + { + return other is LogMessageEntity entity && this.Equals(entity); + } + + /// + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj is LogMessageEntity entity && this.Equals(entity); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(this.Name, this.HomeWorldId, this.ObjStrId, this.Sex, this.IsPlayer); + } +} diff --git a/Dalamud/Game/Gui/ChatGui.cs b/Dalamud/Game/Gui/ChatGui.cs index 30e2b676c..5208c019b 100644 --- a/Dalamud/Game/Gui/ChatGui.cs +++ b/Dalamud/Game/Gui/ChatGui.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Dalamud.Configuration.Internal; @@ -41,10 +42,12 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui private readonly Queue chatQueue = new(); private readonly Dictionary<(string PluginName, uint CommandId), Action> dalamudLinkHandlers = new(); + private readonly List seenLogMessageObjects = new(); private readonly Hook printMessageHook; private readonly Hook inventoryItemCopyHook; private readonly Hook handleLinkClickHook; + private readonly Hook handleLogModuleUpdate; [ServiceManager.ServiceDependency] private readonly DalamudConfiguration configuration = Service.Get(); @@ -58,10 +61,12 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui this.printMessageHook = Hook.FromAddress(RaptureLogModule.Addresses.PrintMessage.Value, this.HandlePrintMessageDetour); this.inventoryItemCopyHook = Hook.FromAddress((nint)InventoryItem.StaticVirtualTablePointer->Copy, this.InventoryItemCopyDetour); this.handleLinkClickHook = Hook.FromAddress(LogViewer.Addresses.HandleLinkClick.Value, this.HandleLinkClickDetour); + this.handleLogModuleUpdate = Hook.FromAddress(RaptureLogModule.Addresses.Update.Value, this.UpdateDetour); this.printMessageHook.Enable(); this.inventoryItemCopyHook.Enable(); this.handleLinkClickHook.Enable(); + this.handleLogModuleUpdate.Enable(); } [UnmanagedFunctionPointer(CallingConvention.ThisCall)] @@ -79,6 +84,9 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui /// public event IChatGui.OnMessageUnhandledDelegate? ChatMessageUnhandled; + /// + public event IChatGui.OnLogMessageDelegate? LogMessage; + /// public uint LastLinkedItemId { get; private set; } @@ -110,6 +118,7 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui this.printMessageHook.Dispose(); this.inventoryItemCopyHook.Dispose(); this.handleLinkClickHook.Dispose(); + this.handleLogModuleUpdate.Dispose(); } #region DalamudSeString @@ -493,6 +502,46 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui Log.Error(ex, "Exception in HandleLinkClickDetour"); } } + + private void UpdateDetour(RaptureLogModule* thisPtr) + { + try + { + foreach (ref var item in thisPtr->LogMessageQueue) + { + var logMessage = new Chat.LogMessage((LogMessageQueueItem*)Unsafe.AsPointer(ref item)); + + // skip any entries that survived the previous Update call as the event was already called for them + if (this.seenLogMessageObjects.Contains(logMessage.Address)) + continue; + + foreach (var action in Delegate.EnumerateInvocationList(this.LogMessage)) + { + try + { + action(logMessage); + } + catch (Exception e) + { + Log.Error(e, "Could not invoke registered OnLogMessageDelegate for {Name}", action.Method); + } + } + } + + this.handleLogModuleUpdate.Original(thisPtr); + + // record the log messages for that we already called the event, but are still in the queue + this.seenLogMessageObjects.Clear(); + foreach (ref var item in thisPtr->LogMessageQueue) + { + this.seenLogMessageObjects.Add((IntPtr)Unsafe.AsPointer(ref item)); + } + } + catch (Exception ex) + { + Log.Error(ex, "Exception in UpdateDetour"); + } + } } /// @@ -521,6 +570,7 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui this.chatGuiService.CheckMessageHandled += this.OnCheckMessageForward; this.chatGuiService.ChatMessageHandled += this.OnMessageHandledForward; this.chatGuiService.ChatMessageUnhandled += this.OnMessageUnhandledForward; + this.chatGuiService.LogMessage += this.OnLogMessageForward; } /// @@ -535,6 +585,9 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui /// public event IChatGui.OnMessageUnhandledDelegate? ChatMessageUnhandled; + /// + public event IChatGui.OnLogMessageDelegate? LogMessage; + /// public uint LastLinkedItemId => this.chatGuiService.LastLinkedItemId; @@ -551,11 +604,13 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui this.chatGuiService.CheckMessageHandled -= this.OnCheckMessageForward; this.chatGuiService.ChatMessageHandled -= this.OnMessageHandledForward; this.chatGuiService.ChatMessageUnhandled -= this.OnMessageUnhandledForward; + this.chatGuiService.LogMessage -= this.OnLogMessageForward; this.ChatMessage = null; this.CheckMessageHandled = null; this.ChatMessageHandled = null; this.ChatMessageUnhandled = null; + this.LogMessage = null; } /// @@ -609,4 +664,7 @@ internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui private void OnMessageUnhandledForward(XivChatType type, int timestamp, SeString sender, SeString message) => this.ChatMessageUnhandled?.Invoke(type, timestamp, sender, message); + + private void OnLogMessageForward(Chat.ILogMessage message) + => this.LogMessage?.Invoke(message); } diff --git a/Dalamud/Plugin/Services/IChatGui.cs b/Dalamud/Plugin/Services/IChatGui.cs index 572ac6c95..eec25cb5a 100644 --- a/Dalamud/Plugin/Services/IChatGui.cs +++ b/Dalamud/Plugin/Services/IChatGui.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; +using Dalamud.Game.Chat; using Dalamud.Game.Gui; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; @@ -50,6 +51,13 @@ public interface IChatGui : IDalamudService /// The message sent. public delegate void OnMessageUnhandledDelegate(XivChatType type, int timestamp, SeString sender, SeString message); + + /// + /// A delegate type used with the event. + /// + /// The message sent. + public delegate void OnLogMessageDelegate(ILogMessage message); + /// /// Event that will be fired when a chat message is sent to chat by the game. /// @@ -70,6 +78,11 @@ public interface IChatGui : IDalamudService /// public event OnMessageUnhandledDelegate ChatMessageUnhandled; + /// + /// Event that will be fired when a log message, that is a chat message based on entries in the LogMessage sheet, is sent. + /// + public event OnLogMessageDelegate LogMessage; + /// /// Gets the ID of the last linked item. /// From b2397efb25075b0b939f5eb5def9cde86b6e971a Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Mon, 22 Dec 2025 20:21:07 +0100 Subject: [PATCH 03/99] Add Self Test --- .../SelfTest/Steps/ChatSelfTestStep.cs | 78 +++++++++++++++++-- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs index 7a2631fbf..16fd3b01e 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs @@ -1,4 +1,5 @@ using Dalamud.Bindings.ImGui; +using Dalamud.Game.Chat; using Dalamud.Game.Gui; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; @@ -12,8 +13,12 @@ namespace Dalamud.Interface.Internal.Windows.SelfTest.Steps; internal class ChatSelfTestStep : ISelfTestStep { private int step = 0; - private bool subscribed = false; + private bool subscribedChatMessage = false; + private bool subscribedLogMessage = false; private bool hasPassed = false; + private bool hasTeleportGil = false; + private bool hasTeleportTicket = false; + private int teleportCount = 0; /// public string Name => "Test Chat"; @@ -34,20 +39,63 @@ internal class ChatSelfTestStep : ISelfTestStep case 1: ImGui.Text("Type \"/e DALAMUD\" in chat..."); - if (!this.subscribed) + if (!this.subscribedChatMessage) { - this.subscribed = true; + this.subscribedChatMessage = true; chatGui.ChatMessage += this.ChatOnOnChatMessage; } if (this.hasPassed) { chatGui.ChatMessage -= this.ChatOnOnChatMessage; - this.subscribed = false; - return SelfTestStepResult.Pass; + this.subscribedChatMessage = false; + this.step++; } break; + + case 2: + ImGui.Text("Teleport somewhere..."); + + if (!this.subscribedLogMessage) + { + this.subscribedLogMessage = true; + chatGui.LogMessage += this.ChatOnLogMessage; + } + + if (this.hasTeleportGil) + { + ImGui.Text($"You spent {this.teleportCount} gil to teleport."); + } + if (this.hasTeleportTicket) + { + ImGui.Text($"You used a ticket to teleport and have {this.teleportCount} remaining."); + } + + if (this.hasTeleportGil || this.hasTeleportTicket) + { + ImGui.Text("Is this correct?"); + + if (ImGui.Button("Yes")) + { + chatGui.LogMessage -= this.ChatOnLogMessage; + this.subscribedLogMessage = false; + this.step++; + } + + ImGui.SameLine(); + if (ImGui.Button("No")) + { + chatGui.LogMessage -= this.ChatOnLogMessage; + this.subscribedLogMessage = false; + return SelfTestStepResult.Fail; + } + } + + break; + + default: + return SelfTestStepResult.Pass; } return SelfTestStepResult.Waiting; @@ -59,7 +107,9 @@ internal class ChatSelfTestStep : ISelfTestStep var chatGui = Service.Get(); chatGui.ChatMessage -= this.ChatOnOnChatMessage; - this.subscribed = false; + chatGui.LogMessage -= this.ChatOnLogMessage; + this.subscribedChatMessage = false; + this.subscribedLogMessage = false; } private void ChatOnOnChatMessage( @@ -70,4 +120,20 @@ internal class ChatSelfTestStep : ISelfTestStep this.hasPassed = true; } } + + private void ChatOnLogMessage(ILogMessage message) + { + if (message.LogMessageId == 4590 && message.TryGetIntParameter(0, out var value)) + { + this.hasTeleportGil = true; + this.hasTeleportTicket = false; + this.teleportCount = value; + } + if (message.LogMessageId == 4591 && message.TryGetIntParameter(0, out var item) && item == 7569 && message.TryGetIntParameter(1, out var remaining)) + { + this.hasTeleportGil = false; + this.hasTeleportTicket = true; + this.teleportCount = remaining; + } + } } From 3aca09d0fb7fa94c769a898b68d96f7d6e630983 Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Mon, 22 Dec 2025 22:28:44 +0100 Subject: [PATCH 04/99] review --- Dalamud/Game/Chat/LogMessage.cs | 10 ++++++---- Dalamud/Game/Gui/ChatGui.cs | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Dalamud/Game/Chat/LogMessage.cs b/Dalamud/Game/Chat/LogMessage.cs index cf423bd6e..92217e1c6 100644 --- a/Dalamud/Game/Chat/LogMessage.cs +++ b/Dalamud/Game/Chat/LogMessage.cs @@ -12,7 +12,7 @@ using Lumina.Excel; using System.Diagnostics.CodeAnalysis; -using TerraFX.Interop.Windows; +using Lumina.Text.ReadOnly; namespace Dalamud.Game.Chat; @@ -72,7 +72,7 @@ public interface ILogMessage : IEquatable /// /// This can cause side effects such as playing sound effects and thus should only be used for debugging. /// The formatted string. - SeString FormatLogMessageForDebugging(); + ReadOnlySeString FormatLogMessageForDebugging(); } /// @@ -144,7 +144,7 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa } /// - public SeString FormatLogMessageForDebugging() + public ReadOnlySeString FormatLogMessageForDebugging() { var logModule = RaptureLogModule.Instance(); @@ -155,7 +155,9 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa SetName(logModule, this.TargetEntity); logModule->RaptureTextModule->FormatString(this.GameData.Value.Text.ToDalamudString().EncodeWithNullTerminator(), &ptr->Parameters, &utf8); - return SeString.Parse(utf8.AsSpan()); + var result = new ReadOnlySeString(utf8.AsSpan()); + utf8.Dtor(); + return result; void SetName(RaptureLogModule* self, LogMessageEntity item) { diff --git a/Dalamud/Game/Gui/ChatGui.cs b/Dalamud/Game/Gui/ChatGui.cs index 5208c019b..c6405fb35 100644 --- a/Dalamud/Game/Gui/ChatGui.cs +++ b/Dalamud/Game/Gui/ChatGui.cs @@ -42,7 +42,7 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui private readonly Queue chatQueue = new(); private readonly Dictionary<(string PluginName, uint CommandId), Action> dalamudLinkHandlers = new(); - private readonly List seenLogMessageObjects = new(); + private readonly List seenLogMessageObjects = new(); private readonly Hook printMessageHook; private readonly Hook inventoryItemCopyHook; @@ -534,7 +534,7 @@ internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui this.seenLogMessageObjects.Clear(); foreach (ref var item in thisPtr->LogMessageQueue) { - this.seenLogMessageObjects.Add((IntPtr)Unsafe.AsPointer(ref item)); + this.seenLogMessageObjects.Add((nint)Unsafe.AsPointer(ref item)); } } catch (Exception ex) From 9da178ad569f6ff0809e1c6e023b54b962521b0e Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Tue, 23 Dec 2025 12:34:04 +0100 Subject: [PATCH 05/99] review (2) --- Dalamud/Game/Chat/LogMessage.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Dalamud/Game/Chat/LogMessage.cs b/Dalamud/Game/Chat/LogMessage.cs index 92217e1c6..fbe3dec3f 100644 --- a/Dalamud/Game/Chat/LogMessage.cs +++ b/Dalamud/Game/Chat/LogMessage.cs @@ -150,14 +150,12 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa // the formatting logic is taken from RaptureLogModule_Update - var utf8 = new Utf8String(); + using var utf8 = new Utf8String(); SetName(logModule, this.SourceEntity); SetName(logModule, this.TargetEntity); logModule->RaptureTextModule->FormatString(this.GameData.Value.Text.ToDalamudString().EncodeWithNullTerminator(), &ptr->Parameters, &utf8); - var result = new ReadOnlySeString(utf8.AsSpan()); - utf8.Dtor(); - return result; + return new ReadOnlySeString(utf8.AsSpan()); void SetName(RaptureLogModule* self, LogMessageEntity item) { From f76d77f79d09972d07cfd8aa030f2a560af17dc1 Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Tue, 23 Dec 2025 12:41:46 +0100 Subject: [PATCH 06/99] rewview (3) and fix some copy docs comments --- Dalamud/Game/Chat/LogMessage.cs | 4 ++-- Dalamud/Game/Chat/LogMessageEntity.cs | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Dalamud/Game/Chat/LogMessage.cs b/Dalamud/Game/Chat/LogMessage.cs index fbe3dec3f..931b3fb3a 100644 --- a/Dalamud/Game/Chat/LogMessage.cs +++ b/Dalamud/Game/Chat/LogMessage.cs @@ -76,9 +76,9 @@ public interface ILogMessage : IEquatable } /// -/// This struct represents a status effect an actor is afflicted by. +/// This struct represents log message in the queue to be added to the chat. /// -/// A pointer to the Status. +/// A pointer to the log message. internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessage { /// diff --git a/Dalamud/Game/Chat/LogMessageEntity.cs b/Dalamud/Game/Chat/LogMessageEntity.cs index e4c81c16a..b465dc158 100644 --- a/Dalamud/Game/Chat/LogMessageEntity.cs +++ b/Dalamud/Game/Chat/LogMessageEntity.cs @@ -1,13 +1,13 @@ using System.Diagnostics.CodeAnalysis; using Dalamud.Data; -using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.UI.Misc; using Lumina.Excel; using Lumina.Excel.Sheets; +using Lumina.Text.ReadOnly; namespace Dalamud.Game.Chat; @@ -19,7 +19,7 @@ public interface ILogMessageEntity : IEquatable /// /// Gets the name of this entity. /// - SeString Name { get; } + ReadOnlySeString Name { get; } /// /// Gets the ID of the homeworld of this entity, if it is a player. @@ -44,14 +44,15 @@ public interface ILogMessageEntity : IEquatable /// -/// This struct represents a status effect an actor is afflicted by. +/// This struct represents an entity related to a log message. /// -/// A pointer to the Status. +/// A pointer to the log message item. +/// If represents the source entity of the log message, otherwise represents the target entity internal unsafe readonly struct LogMessageEntity(LogMessageQueueItem* ptr, bool source) : ILogMessageEntity { public Span NameSpan => source ? ptr->SourceName : ptr->TargetName; - public SeString Name => SeString.Parse(this.NameSpan); + public ReadOnlySeString Name => new ReadOnlySeString(this.NameSpan); public ushort HomeWorldId => source ? ptr->SourceHomeWorld : ptr->TargetHomeWorld; From 186b1b83765cd17d58fd70dc6c53a26af70b85ff Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:58:47 +0100 Subject: [PATCH 07/99] Use SeStringEvaluator instead of RaptureTextModule for the debug display --- Dalamud/Game/Chat/LogMessage.cs | 13 +++++-------- Dalamud/Game/Text/Evaluator/SeStringParameter.cs | 10 ++++++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Dalamud/Game/Chat/LogMessage.cs b/Dalamud/Game/Chat/LogMessage.cs index 931b3fb3a..37b341428 100644 --- a/Dalamud/Game/Chat/LogMessage.cs +++ b/Dalamud/Game/Chat/LogMessage.cs @@ -1,18 +1,18 @@ using Dalamud.Data; +using Dalamud.Game.Text.Evaluator; using Dalamud.Game.Text.SeStringHandling; -using Dalamud.Utility; -using FFXIVClientStructs.FFXIV.Client.System.String; + using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Client.UI.Misc; using FFXIVClientStructs.FFXIV.Component.Text; using FFXIVClientStructs.Interop; using Lumina.Excel; +using Lumina.Text.ReadOnly; using System.Diagnostics.CodeAnalysis; - -using Lumina.Text.ReadOnly; +using System.Linq; namespace Dalamud.Game.Chat; @@ -150,12 +150,9 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa // the formatting logic is taken from RaptureLogModule_Update - using var utf8 = new Utf8String(); SetName(logModule, this.SourceEntity); SetName(logModule, this.TargetEntity); - logModule->RaptureTextModule->FormatString(this.GameData.Value.Text.ToDalamudString().EncodeWithNullTerminator(), &ptr->Parameters, &utf8); - - return new ReadOnlySeString(utf8.AsSpan()); + return Service.Get().EvaluateFromLogMessage(this.LogMessageId, ptr->Parameters.Select(p => (SeStringParameter)p).ToArray()); void SetName(RaptureLogModule* self, LogMessageEntity item) { diff --git a/Dalamud/Game/Text/Evaluator/SeStringParameter.cs b/Dalamud/Game/Text/Evaluator/SeStringParameter.cs index 036d1c921..a8fe3b3b9 100644 --- a/Dalamud/Game/Text/Evaluator/SeStringParameter.cs +++ b/Dalamud/Game/Text/Evaluator/SeStringParameter.cs @@ -1,5 +1,7 @@ using System.Globalization; +using FFXIVClientStructs.FFXIV.Component.Text; + using Lumina.Text.ReadOnly; using DSeString = Dalamud.Game.Text.SeStringHandling.SeString; @@ -75,4 +77,12 @@ public readonly struct SeStringParameter public static implicit operator SeStringParameter(string value) => new(value); public static implicit operator SeStringParameter(ReadOnlySpan value) => new(value); + + public static unsafe implicit operator SeStringParameter(TextParameter value) => value.Type switch + { + TextParameterType.Uninitialized => default, + TextParameterType.Integer => new((uint)value.IntValue), + TextParameterType.ReferencedUtf8String => new(new ReadOnlySeString(value.ReferencedUtf8StringValue->Utf8String.AsSpan())), + TextParameterType.String => new(value.StringValue), + }; } From bf75937cc05d542504039d375efdf477d6f2e435 Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Tue, 23 Dec 2025 21:01:29 +0100 Subject: [PATCH 08/99] Don't go through SeString to null terminate a string --- Dalamud/Game/Chat/LogMessage.cs | 12 ++++++++---- Dalamud/Game/Text/Evaluator/SeStringParameter.cs | 10 ---------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Dalamud/Game/Chat/LogMessage.cs b/Dalamud/Game/Chat/LogMessage.cs index 37b341428..5d59a84ee 100644 --- a/Dalamud/Game/Chat/LogMessage.cs +++ b/Dalamud/Game/Chat/LogMessage.cs @@ -1,8 +1,8 @@ using Dalamud.Data; -using Dalamud.Game.Text.Evaluator; using Dalamud.Game.Text.SeStringHandling; +using Dalamud.Utility; - +using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Client.UI.Misc; using FFXIVClientStructs.FFXIV.Component.Text; @@ -12,7 +12,6 @@ using Lumina.Excel; using Lumina.Text.ReadOnly; using System.Diagnostics.CodeAnalysis; -using System.Linq; namespace Dalamud.Game.Chat; @@ -150,9 +149,14 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa // the formatting logic is taken from RaptureLogModule_Update + using var utf8 = new Utf8String(); SetName(logModule, this.SourceEntity); SetName(logModule, this.TargetEntity); - return Service.Get().EvaluateFromLogMessage(this.LogMessageId, ptr->Parameters.Select(p => (SeStringParameter)p).ToArray()); + + using var rssb = new RentedSeStringBuilder(); + logModule->RaptureTextModule->FormatString(rssb.Builder.Append(this.GameData.Value.Text).GetViewAsSpan(), &ptr->Parameters, &utf8); + + return new ReadOnlySeString(utf8.AsSpan()); void SetName(RaptureLogModule* self, LogMessageEntity item) { diff --git a/Dalamud/Game/Text/Evaluator/SeStringParameter.cs b/Dalamud/Game/Text/Evaluator/SeStringParameter.cs index a8fe3b3b9..036d1c921 100644 --- a/Dalamud/Game/Text/Evaluator/SeStringParameter.cs +++ b/Dalamud/Game/Text/Evaluator/SeStringParameter.cs @@ -1,7 +1,5 @@ using System.Globalization; -using FFXIVClientStructs.FFXIV.Component.Text; - using Lumina.Text.ReadOnly; using DSeString = Dalamud.Game.Text.SeStringHandling.SeString; @@ -77,12 +75,4 @@ public readonly struct SeStringParameter public static implicit operator SeStringParameter(string value) => new(value); public static implicit operator SeStringParameter(ReadOnlySpan value) => new(value); - - public static unsafe implicit operator SeStringParameter(TextParameter value) => value.Type switch - { - TextParameterType.Uninitialized => default, - TextParameterType.Integer => new((uint)value.IntValue), - TextParameterType.ReferencedUtf8String => new(new ReadOnlySeString(value.ReferencedUtf8StringValue->Utf8String.AsSpan())), - TextParameterType.String => new(value.StringValue), - }; } From 65c604f8272b6083175cd42945b4983b2f5cce98 Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Wed, 24 Dec 2025 11:13:06 +0100 Subject: [PATCH 09/99] More ReadOnlySeString things --- Dalamud/Game/Chat/LogMessage.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Dalamud/Game/Chat/LogMessage.cs b/Dalamud/Game/Chat/LogMessage.cs index 5d59a84ee..93b928d48 100644 --- a/Dalamud/Game/Chat/LogMessage.cs +++ b/Dalamud/Game/Chat/LogMessage.cs @@ -1,5 +1,4 @@ using Dalamud.Data; -using Dalamud.Game.Text.SeStringHandling; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.System.String; @@ -64,7 +63,7 @@ public interface ILogMessage : IEquatable /// The index of the parameter to retrieve. /// The value of the parameter. /// if the parameter was retrieved successfully. - bool TryGetStringParameter(int index, [NotNullWhen(true)] out SeString? value); + bool TryGetStringParameter(int index, out ReadOnlySeString value); /// /// Formats this log message into an approximation of the string that will eventually be shown in the log. @@ -124,18 +123,18 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa } /// - public bool TryGetStringParameter(int index, [NotNullWhen(true)] out SeString? value) + public bool TryGetStringParameter(int index, out ReadOnlySeString value) { - value = null; + value = default; if (!this.TryGetParameter(index, out var parameter)) return false; if (parameter.Type == TextParameterType.String) { - value = SeString.Parse(parameter.StringValue.Value); + value = new(parameter.StringValue.AsSpan()); return true; } if (parameter.Type == TextParameterType.ReferencedUtf8String) { - value = SeString.Parse(parameter.ReferencedUtf8StringValue->Utf8String.AsSpan()); + value = new(parameter.ReferencedUtf8StringValue->Utf8String.AsSpan()); return true; } From 31cbf4d8eb47782cd332f41e0af8b74d10ebfb8a Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Wed, 24 Dec 2025 12:17:57 +0100 Subject: [PATCH 10/99] Respect null-termination of entity names --- Dalamud/Game/Chat/LogMessageEntity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Game/Chat/LogMessageEntity.cs b/Dalamud/Game/Chat/LogMessageEntity.cs index b465dc158..4294e4898 100644 --- a/Dalamud/Game/Chat/LogMessageEntity.cs +++ b/Dalamud/Game/Chat/LogMessageEntity.cs @@ -52,7 +52,7 @@ internal unsafe readonly struct LogMessageEntity(LogMessageQueueItem* ptr, bool { public Span NameSpan => source ? ptr->SourceName : ptr->TargetName; - public ReadOnlySeString Name => new ReadOnlySeString(this.NameSpan); + public ReadOnlySeString Name => new ReadOnlySeString(this.NameSpan[..this.NameSpan.IndexOf((byte)0)]); public ushort HomeWorldId => source ? ptr->SourceHomeWorld : ptr->TargetHomeWorld; From c559426d8b6da76952b04a4cefc18fa6494d2c91 Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Wed, 24 Dec 2025 12:23:24 +0100 Subject: [PATCH 11/99] Add Data Widget --- .../Internal/Windows/Data/DataWindow.cs | 1 + .../Data/Widgets/LogMessageMonitorWidget.cs | 156 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 Dalamud/Interface/Internal/Windows/Data/Widgets/LogMessageMonitorWidget.cs diff --git a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs index eb0589d59..154fc8c02 100644 --- a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs @@ -44,6 +44,7 @@ internal class DataWindow : Window, IDisposable new ImGuiWidget(), new InventoryWidget(), new KeyStateWidget(), + new LogMessageMonitorWidget(), new MarketBoardWidget(), new NetworkMonitorWidget(), new NounProcessorWidget(), diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/LogMessageMonitorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/LogMessageMonitorWidget.cs new file mode 100644 index 000000000..fde46f0c7 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/LogMessageMonitorWidget.cs @@ -0,0 +1,156 @@ +using System.Buffers; +using System.Collections.Concurrent; +using System.Linq; +using System.Text.Json; +using System.Text.RegularExpressions; + +using Dalamud.Bindings.ImGui; +using Dalamud.Game.Chat; +using Dalamud.Game.Gui; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; + +using Lumina.Text.ReadOnly; + +using ImGuiTable = Dalamud.Interface.Utility.ImGuiTable; + +namespace Dalamud.Interface.Internal.Windows.Data.Widgets; + +/// +/// Widget to display the LogMessages. +/// +internal class LogMessageMonitorWidget : IDataWindowWidget +{ + private readonly ConcurrentQueue messages = new(); + + private bool trackMessages; + private int trackedMessages; + private Regex? filterRegex; + private string filterString = string.Empty; + + /// + public string[]? CommandShortcuts { get; init; } = ["logmessage"]; + + /// + public string DisplayName { get; init; } = "LogMessage Monitor"; + + /// + public bool Ready { get; set; } + + /// + public void Load() + { + this.trackMessages = false; + this.trackedMessages = 20; + this.filterRegex = null; + this.filterString = string.Empty; + this.messages.Clear(); + this.Ready = true; + } + + /// + public void Draw() + { + var network = Service.Get(); + if (ImGui.Checkbox("Track LogMessages"u8, ref this.trackMessages)) + { + if (this.trackMessages) + { + network.LogMessage += this.OnLogMessage; + } + else + { + network.LogMessage -= this.OnLogMessage; + } + } + + ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X / 2); + if (ImGui.DragInt("Stored Number of Messages"u8, ref this.trackedMessages, 0.1f, 1, 512)) + { + this.trackedMessages = Math.Clamp(this.trackedMessages, 1, 512); + } + + if (ImGui.Button("Clear Stored Messages"u8)) + { + this.messages.Clear(); + } + + this.DrawFilterInput(); + + ImGuiTable.DrawTable(string.Empty, this.messages.Where(m => this.filterRegex == null || this.filterRegex.IsMatch(m.Formatted.ExtractText())), this.DrawNetworkPacket, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingStretchProp, "LogMessageId", "Source", "Target", "Parameters", "Formatted"); + } + + private void DrawNetworkPacket(LogMessageData data) + { + ImGui.TableNextColumn(); + ImGui.Text(data.LogMessageId.ToString()); + + ImGui.TableNextColumn(); + ImGuiHelpers.SeStringWrapped(data.Source); + + ImGui.TableNextColumn(); + ImGuiHelpers.SeStringWrapped(data.Target); + + ImGui.TableNextColumn(); + ImGui.Text(data.Parameters); + + ImGui.TableNextColumn(); + ImGuiHelpers.SeStringWrapped(data.Formatted); + } + + private void DrawFilterInput() + { + var invalidRegEx = this.filterString.Length > 0 && this.filterRegex == null; + using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, invalidRegEx); + using var color = ImRaii.PushColor(ImGuiCol.Border, 0xFF0000FF, invalidRegEx); + ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); + if (!ImGui.InputTextWithHint("##Filter"u8, "Regex Filter..."u8, ref this.filterString, 1024)) + { + return; + } + + if (this.filterString.Length == 0) + { + this.filterRegex = null; + } + else + { + try + { + this.filterRegex = new Regex(this.filterString, RegexOptions.Compiled | RegexOptions.ExplicitCapture); + } + catch + { + this.filterRegex = null; + } + } + } + + private void OnLogMessage(ILogMessage message) + { + var buffer = new ArrayBufferWriter(); + var writer = new Utf8JsonWriter(buffer); + + writer.WriteStartArray(); + for (var i = 0; i < message.ParameterCount; i++) + { + if (message.TryGetStringParameter(i, out var str)) + writer.WriteStringValue(str.ExtractText()); + else if (message.TryGetIntParameter(i, out var num)) + writer.WriteNumberValue(num); + else + writer.WriteNullValue(); + } + + writer.WriteEndArray(); + writer.Flush(); + + this.messages.Enqueue(new LogMessageData(message.LogMessageId, message.SourceEntity?.Name ?? default, message.TargetEntity?.Name ?? default, buffer.WrittenMemory, message.FormatLogMessageForDebugging())); + while (this.messages.Count > this.trackedMessages) + { + this.messages.TryDequeue(out _); + } + } + + private readonly record struct LogMessageData(uint LogMessageId, ReadOnlySeString Source, ReadOnlySeString Target, ReadOnlyMemory Parameters, ReadOnlySeString Formatted); +} From c00363badfe4946fa6cb82df62b8369c67341d26 Mon Sep 17 00:00:00 2001 From: goat Date: Thu, 25 Dec 2025 11:31:47 +0100 Subject: [PATCH 12/99] build: 14.0.0.3 --- Dalamud/Dalamud.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 5f79eb274..f5e75af63 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -6,7 +6,7 @@ XIV Launcher addon framework - 14.0.0.2 + 14.0.0.3 $(DalamudVersion) $(DalamudVersion) $(DalamudVersion) From 558a011e00cb85b3b306a524e38f51d76e342625 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 26 Dec 2025 15:02:13 +0000 Subject: [PATCH 13/99] Update Excel Schema --- lib/Lumina.Excel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Lumina.Excel b/lib/Lumina.Excel index d6ff8cf46..c4ea8bafd 160000 --- a/lib/Lumina.Excel +++ b/lib/Lumina.Excel @@ -1 +1 @@ -Subproject commit d6ff8cf46c7e341989843c28c7550f8d50bee851 +Subproject commit c4ea8bafda8d88d49a390014dd3b86457f2dc7d5 From 689d2f01d9cd642bb77a249c22eac6c8d9884d67 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 26 Dec 2025 15:02:13 +0000 Subject: [PATCH 14/99] Update ClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 9c5f93cf3..2c3b35dd7 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 9c5f93cf3ac57236656cd2323b93cd258ea84a88 +Subproject commit 2c3b35dd7da71a94b517536affa180fd0e7dc403 From 62b8b0834cefa190e749a67a311ecc3e92dfc346 Mon Sep 17 00:00:00 2001 From: goat Date: Fri, 26 Dec 2025 16:09:32 +0100 Subject: [PATCH 15/99] Use v145 build tools for C++ components --- Dalamud.Boot/Dalamud.Boot.vcxproj | 4 ++-- DalamudCrashHandler/DalamudCrashHandler.vcxproj | 4 ++-- external/cimgui/cimgui.vcxproj | 6 +++--- external/cimguizmo/cimguizmo.vcxproj | 6 +++--- external/cimplot/cimplot.vcxproj | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Dalamud.Boot/Dalamud.Boot.vcxproj b/Dalamud.Boot/Dalamud.Boot.vcxproj index 0a4a9c563..20c107be2 100644 --- a/Dalamud.Boot/Dalamud.Boot.vcxproj +++ b/Dalamud.Boot/Dalamud.Boot.vcxproj @@ -25,7 +25,7 @@ DynamicLibrary true - v143 + v145 false Unicode bin\$(Configuration)\ @@ -211,4 +211,4 @@ - \ No newline at end of file + diff --git a/DalamudCrashHandler/DalamudCrashHandler.vcxproj b/DalamudCrashHandler/DalamudCrashHandler.vcxproj index 00d67cd65..e332b7b03 100644 --- a/DalamudCrashHandler/DalamudCrashHandler.vcxproj +++ b/DalamudCrashHandler/DalamudCrashHandler.vcxproj @@ -25,7 +25,7 @@ Application true - v143 + v145 false Unicode ..\bin\$(Configuration)\ @@ -95,4 +95,4 @@ - \ No newline at end of file + diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj index d99d23119..e047718ac 100644 --- a/external/cimgui/cimgui.vcxproj +++ b/external/cimgui/cimgui.vcxproj @@ -35,13 +35,13 @@ DynamicLibrary true - v143 + v145 Unicode DynamicLibrary false - v143 + v145 true Unicode @@ -106,4 +106,4 @@ - \ No newline at end of file + diff --git a/external/cimguizmo/cimguizmo.vcxproj b/external/cimguizmo/cimguizmo.vcxproj index 9bf692d4b..b3d66fb81 100644 --- a/external/cimguizmo/cimguizmo.vcxproj +++ b/external/cimguizmo/cimguizmo.vcxproj @@ -37,13 +37,13 @@ DynamicLibrary true - v143 + v145 Unicode DynamicLibrary false - v143 + v145 true Unicode @@ -108,4 +108,4 @@ - \ No newline at end of file + diff --git a/external/cimplot/cimplot.vcxproj b/external/cimplot/cimplot.vcxproj index e9aecbc15..cdc4226bf 100644 --- a/external/cimplot/cimplot.vcxproj +++ b/external/cimplot/cimplot.vcxproj @@ -35,13 +35,13 @@ DynamicLibrary true - v143 + v145 Unicode DynamicLibrary false - v143 + v145 true Unicode @@ -106,4 +106,4 @@ - \ No newline at end of file + From a659cd8a49df7c7370d7596e946202e9c5d1d3be Mon Sep 17 00:00:00 2001 From: goat Date: Fri, 26 Dec 2025 16:15:51 +0100 Subject: [PATCH 16/99] Adjust to Excel renames --- .../Internal/Windows/Data/Widgets/UIColorWidget.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs index 3550f053c..fd3f1d11c 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs @@ -126,17 +126,17 @@ internal class UiColorWidget : IDataWindowWidget ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.PushID($"row{id}_white"); - if (this.DrawColorColumn(row.Unknown0) && + if (this.DrawColorColumn(row.ClearWhite) && adjacentRow.HasValue) - DrawEdgePreview(id, row.Unknown0, adjacentRow.Value.Unknown0); + DrawEdgePreview(id, row.ClearWhite, adjacentRow.Value.ClearWhite); ImGui.PopID(); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); ImGui.PushID($"row{id}_green"); - if (this.DrawColorColumn(row.Unknown1) && + if (this.DrawColorColumn(row.ClearGreen) && adjacentRow.HasValue) - DrawEdgePreview(id, row.Unknown1, adjacentRow.Value.Unknown1); + DrawEdgePreview(id, row.ClearGreen, adjacentRow.Value.ClearGreen); ImGui.PopID(); } } From fc130e325cf967069e8c0b0b9026dd3833af42fc Mon Sep 17 00:00:00 2001 From: goat Date: Fri, 26 Dec 2025 16:15:58 +0100 Subject: [PATCH 17/99] Fix warnings --- Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs index 4d858922a..56ed45446 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs @@ -25,9 +25,10 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class UldWidget : IDataWindowWidget { + private const string UldBaseBath = "ui/uld/"; + // ULD styles can be hardcoded for now as they don't add new ones regularly. Can later try and find where to load these from in the game EXE. private static readonly string[] ThemeDisplayNames = ["Dark", "Light", "Classic FF", "Clear Blue", "Clear White", "Clear Green"]; - private const string UldBaseBath = "ui/uld/"; // 48 8D 15 ?? ?? ?? ?? is the part of the signatures that contain the string location offset // 48 = 64 bit register prefix @@ -263,7 +264,7 @@ internal class UldWidget : IDataWindowWidget } private string ToThemedPath(string path) => - UldBaseBath + (this.selectedTheme > 0 ? $"img{this.selectedTheme:D2}" : "") + path[UldBaseBath.Length..]; + UldBaseBath + (this.selectedTheme > 0 ? $"img{this.selectedTheme:D2}" : string.Empty) + path[UldBaseBath.Length..]; private void DrawTextureEntry(UldRoot.TextureEntry textureEntry, TextureManager textureManager) { From 79ce2fff0aba5eaa827d5c7696fb0b07f790e865 Mon Sep 17 00:00:00 2001 From: goaaats Date: Wed, 31 Dec 2025 12:15:18 +0100 Subject: [PATCH 18/99] Revert "Use v145 build tools for C++ components" This reverts commit 62b8b0834cefa190e749a67a311ecc3e92dfc346. MS can't manage to get actions images with 2026 for some reason. --- Dalamud.Boot/Dalamud.Boot.vcxproj | 4 ++-- DalamudCrashHandler/DalamudCrashHandler.vcxproj | 4 ++-- external/cimgui/cimgui.vcxproj | 6 +++--- external/cimguizmo/cimguizmo.vcxproj | 6 +++--- external/cimplot/cimplot.vcxproj | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Dalamud.Boot/Dalamud.Boot.vcxproj b/Dalamud.Boot/Dalamud.Boot.vcxproj index 20c107be2..0a4a9c563 100644 --- a/Dalamud.Boot/Dalamud.Boot.vcxproj +++ b/Dalamud.Boot/Dalamud.Boot.vcxproj @@ -25,7 +25,7 @@ DynamicLibrary true - v145 + v143 false Unicode bin\$(Configuration)\ @@ -211,4 +211,4 @@ - + \ No newline at end of file diff --git a/DalamudCrashHandler/DalamudCrashHandler.vcxproj b/DalamudCrashHandler/DalamudCrashHandler.vcxproj index e332b7b03..00d67cd65 100644 --- a/DalamudCrashHandler/DalamudCrashHandler.vcxproj +++ b/DalamudCrashHandler/DalamudCrashHandler.vcxproj @@ -25,7 +25,7 @@ Application true - v145 + v143 false Unicode ..\bin\$(Configuration)\ @@ -95,4 +95,4 @@ - + \ No newline at end of file diff --git a/external/cimgui/cimgui.vcxproj b/external/cimgui/cimgui.vcxproj index e047718ac..d99d23119 100644 --- a/external/cimgui/cimgui.vcxproj +++ b/external/cimgui/cimgui.vcxproj @@ -35,13 +35,13 @@ DynamicLibrary true - v145 + v143 Unicode DynamicLibrary false - v145 + v143 true Unicode @@ -106,4 +106,4 @@ - + \ No newline at end of file diff --git a/external/cimguizmo/cimguizmo.vcxproj b/external/cimguizmo/cimguizmo.vcxproj index b3d66fb81..9bf692d4b 100644 --- a/external/cimguizmo/cimguizmo.vcxproj +++ b/external/cimguizmo/cimguizmo.vcxproj @@ -37,13 +37,13 @@ DynamicLibrary true - v145 + v143 Unicode DynamicLibrary false - v145 + v143 true Unicode @@ -108,4 +108,4 @@ - + \ No newline at end of file diff --git a/external/cimplot/cimplot.vcxproj b/external/cimplot/cimplot.vcxproj index cdc4226bf..e9aecbc15 100644 --- a/external/cimplot/cimplot.vcxproj +++ b/external/cimplot/cimplot.vcxproj @@ -35,13 +35,13 @@ DynamicLibrary true - v145 + v143 Unicode DynamicLibrary false - v145 + v143 true Unicode @@ -106,4 +106,4 @@ - + \ No newline at end of file From 49abb19673c035f2b0db685595089a7567abe817 Mon Sep 17 00:00:00 2001 From: nebel <9887+nebel@users.noreply.github.com> Date: Sat, 3 Jan 2026 00:49:51 +0900 Subject: [PATCH 19/99] Fix font corruption caused by Font Awesome icon button in Data window --- .../Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs index 4f5540daf..ea4b80247 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs @@ -114,7 +114,7 @@ internal class FontAwesomeTestWidget : IDataWindowWidget Task.FromResult( Service.Get().CreateTextureFromSeString( ReadOnlySeString.FromText(this.icons[i].ToIconString()), - new() { Font = ImGui.GetFont(), FontSize = ImGui.GetFontSize() }))); + new() { Font = ImGui.GetFont(), FontSize = ImGui.GetFontSize(), ScreenOffset = Vector2.Zero }))); } ImGui.PopFont(); From bbb6e438b1fd963584a9b4091d03370738a29934 Mon Sep 17 00:00:00 2001 From: bleatbot <106497096+bleatbot@users.noreply.github.com> Date: Sat, 3 Jan 2026 20:31:20 +0100 Subject: [PATCH 20/99] Update ClientStructs (#2556) Co-authored-by: github-actions[bot] --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 2c3b35dd7..e1e99cf46 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 2c3b35dd7da71a94b517536affa180fd0e7dc403 +Subproject commit e1e99cf469f87b0f3e8664ee3e3650dff86df2d6 From 5a0257e40e37ce2b0d77563f2d46c03d4387914f Mon Sep 17 00:00:00 2001 From: bleatbot <106497096+bleatbot@users.noreply.github.com> Date: Sat, 3 Jan 2026 20:31:46 +0100 Subject: [PATCH 21/99] Update Excel Schema (#2555) Co-authored-by: github-actions[bot] --- lib/Lumina.Excel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Lumina.Excel b/lib/Lumina.Excel index c4ea8bafd..52cb5e0a9 160000 --- a/lib/Lumina.Excel +++ b/lib/Lumina.Excel @@ -1 +1 @@ -Subproject commit c4ea8bafda8d88d49a390014dd3b86457f2dc7d5 +Subproject commit 52cb5e0a9a7a1138d8c2406c277307a6c9ad8898 From 9538af05541fb037cf1e5db3126da5f2cc663b61 Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Sat, 3 Jan 2026 20:46:48 +0100 Subject: [PATCH 22/99] UldWidget fixes (#2557) * Fix missing directory separator in theme path * Hide themed texture exception when file not found * Check ThemeSupportBitmask --- .../Windows/Data/Widgets/UldWidget.cs | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs index 56ed45446..7c8110301 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs @@ -47,6 +47,7 @@ internal class UldWidget : IDataWindowWidget ("48 8D 15 ?? ?? ?? ?? 45 33 C0 E9 ?? ?? ?? ??", 3) ]; + private DataManager dataManager; private CancellationTokenSource? cts; private Task? uldNamesTask; @@ -69,6 +70,8 @@ internal class UldWidget : IDataWindowWidget /// public void Load() { + this.dataManager ??= Service.Get(); + this.cts?.Cancel(); ClearTask(ref this.uldNamesTask); this.uldNamesTask = null; @@ -264,7 +267,7 @@ internal class UldWidget : IDataWindowWidget } private string ToThemedPath(string path) => - UldBaseBath + (this.selectedTheme > 0 ? $"img{this.selectedTheme:D2}" : string.Empty) + path[UldBaseBath.Length..]; + UldBaseBath + (this.selectedTheme > 0 ? $"img{this.selectedTheme:D2}/" : string.Empty) + path[UldBaseBath.Length..]; private void DrawTextureEntry(UldRoot.TextureEntry textureEntry, TextureManager textureManager) { @@ -292,14 +295,17 @@ internal class UldWidget : IDataWindowWidget else if (e is not null) ImGui.Text(e.ToString()); - if (this.selectedTheme != 0) + if (this.selectedTheme != 0 && (textureEntry.ThemeSupportBitmask & (1 << (this.selectedTheme - 1))) != 0) { var texturePathThemed = this.ToThemedPath(texturePath); - ImGui.Text($"Themed path at {texturePathThemed}:"); - if (textureManager.Shared.GetFromGame(texturePathThemed).TryGetWrap(out wrap, out e)) - ImGui.Image(wrap.Handle, wrap.Size); - else if (e is not null) - ImGui.Text(e.ToString()); + if (this.dataManager.FileExists(texturePathThemed)) + { + ImGui.Text($"Themed path at {texturePathThemed}:"); + if (textureManager.Shared.GetFromGame(texturePathThemed).TryGetWrap(out wrap, out e)) + ImGui.Image(wrap.Handle, wrap.Size); + else if (e is not null) + ImGui.Text(e.ToString()); + } } ImGui.EndTooltip(); From a1d2e275a78680fa1fc33a693f453189012ab4c5 Mon Sep 17 00:00:00 2001 From: Infi Date: Sat, 3 Jan 2026 20:54:24 +0100 Subject: [PATCH 23/99] - Apply ImRaii to FontAwesomeTestWidget - Adjust array init --- .../Data/Widgets/FontAwesomeTestWidget.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs index ea4b80247..8435f18dd 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs @@ -5,9 +5,11 @@ using System.Threading.Tasks; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; +using Dalamud.Interface.ImGuiSeStringRenderer; using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Internal; +using Dalamud.Interface.Utility.Raii; using Lumina.Text.ReadOnly; @@ -18,13 +20,15 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class FontAwesomeTestWidget : IDataWindowWidget { + private static readonly string[] First = ["(Show All)", "(Undefined)"]; + private List? icons; private List? iconNames; private string[]? iconCategories; private int selectedIconCategory; private string iconSearchInput = string.Empty; private bool iconSearchChanged = true; - private bool useFixedWidth = false; + private bool useFixedWidth; /// public string[]? CommandShortcuts { get; init; } = { "fa", "fatest", "fontawesome" }; @@ -44,11 +48,9 @@ internal class FontAwesomeTestWidget : IDataWindowWidget /// public void Draw() { - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); + using var pushedStyle = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero); - this.iconCategories ??= new[] { "(Show All)", "(Undefined)" } - .Concat(FontAwesomeHelpers.GetCategories().Skip(1)) - .ToArray(); + this.iconCategories ??= First.Concat(FontAwesomeHelpers.GetCategories().Skip(1)).ToArray(); if (this.iconSearchChanged) { @@ -101,7 +103,8 @@ internal class FontAwesomeTestWidget : IDataWindowWidget ImGuiHelpers.ScaledRelativeSameLine(50f); ImGui.Text($"{this.iconNames?[i]}"); ImGuiHelpers.ScaledRelativeSameLine(280f); - ImGui.PushFont(this.useFixedWidth ? InterfaceManager.IconFontFixedWidth : InterfaceManager.IconFont); + + using var pushedFont = ImRaii.PushFont(this.useFixedWidth ? InterfaceManager.IconFontFixedWidth : InterfaceManager.IconFont); ImGui.Text(this.icons[i].ToIconString()); ImGuiHelpers.ScaledRelativeSameLine(320f); if (this.useFixedWidth @@ -114,13 +117,10 @@ internal class FontAwesomeTestWidget : IDataWindowWidget Task.FromResult( Service.Get().CreateTextureFromSeString( ReadOnlySeString.FromText(this.icons[i].ToIconString()), - new() { Font = ImGui.GetFont(), FontSize = ImGui.GetFontSize(), ScreenOffset = Vector2.Zero }))); + new SeStringDrawParams { Font = ImGui.GetFont(), FontSize = ImGui.GetFontSize(), ScreenOffset = Vector2.Zero }))); } - ImGui.PopFont(); ImGuiHelpers.ScaledDummy(2f); } - - ImGui.PopStyleVar(); } } From e44fda19115b1d1f94a5ddcbe90f7d0555ae5c16 Mon Sep 17 00:00:00 2001 From: Infi Date: Sat, 3 Jan 2026 21:04:01 +0100 Subject: [PATCH 24/99] - Apply ImRaii to UIColorWidget --- .../Windows/Data/Widgets/UIColorWidget.cs | 73 ++++++++++--------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs index fd3f1d11c..bc6e5376c 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs @@ -7,6 +7,8 @@ using Dalamud.Data; using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiSeStringRenderer.Internal; +using Dalamud.Interface.Utility.Raii; + using Lumina.Excel.Sheets; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -32,7 +34,7 @@ internal class UiColorWidget : IDataWindowWidget } /// - public unsafe void Draw() + public void Draw() { var colors = Service.GetNullable()?.GetExcelSheet() ?? throw new InvalidOperationException("UIColor sheet not loaded."); @@ -44,7 +46,9 @@ internal class UiColorWidget : IDataWindowWidget "BB.
" + "· Click on a color to copy the color code.
" + "· Hover on a color to preview the text with edge, when the next color has been used together."); - if (!ImGui.BeginTable("UIColor"u8, 7)) + + using var table = ImRaii.Table("UIColor"u8, 7); + if (!table.Success) return; ImGui.TableSetupScrollFreeze(0, 1); @@ -93,61 +97,61 @@ internal class UiColorWidget : IDataWindowWidget ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); - ImGui.PushID($"row{id}_dark"); - if (this.DrawColorColumn(row.Dark) && - adjacentRow.HasValue) - DrawEdgePreview(id, row.Dark, adjacentRow.Value.Dark); - ImGui.PopID(); + using (ImRaii.PushId($"row{id}_dark")) + { + if (this.DrawColorColumn(row.Dark) && adjacentRow.HasValue) + DrawEdgePreview(id, row.Dark, adjacentRow.Value.Dark); + } ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); - ImGui.PushID($"row{id}_light"); - if (this.DrawColorColumn(row.Light) && - adjacentRow.HasValue) - DrawEdgePreview(id, row.Light, adjacentRow.Value.Light); - ImGui.PopID(); + using (ImRaii.PushId($"row{id}_light")) + { + if (this.DrawColorColumn(row.Light) && adjacentRow.HasValue) + DrawEdgePreview(id, row.Light, adjacentRow.Value.Light); + } ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); - ImGui.PushID($"row{id}_classic"); - if (this.DrawColorColumn(row.ClassicFF) && - adjacentRow.HasValue) - DrawEdgePreview(id, row.ClassicFF, adjacentRow.Value.ClassicFF); - ImGui.PopID(); + using (ImRaii.PushId($"row{id}_classic")) + { + if (this.DrawColorColumn(row.ClassicFF) && adjacentRow.HasValue) + DrawEdgePreview(id, row.ClassicFF, adjacentRow.Value.ClassicFF); + } ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); - ImGui.PushID($"row{id}_blue"); - if (this.DrawColorColumn(row.ClearBlue) && - adjacentRow.HasValue) - DrawEdgePreview(id, row.ClearBlue, adjacentRow.Value.ClearBlue); - ImGui.PopID(); + using (ImRaii.PushId($"row{id}_blue")) + { + if (this.DrawColorColumn(row.ClearBlue) && adjacentRow.HasValue) + DrawEdgePreview(id, row.ClearBlue, adjacentRow.Value.ClearBlue); + } ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); - ImGui.PushID($"row{id}_white"); - if (this.DrawColorColumn(row.ClearWhite) && - adjacentRow.HasValue) - DrawEdgePreview(id, row.ClearWhite, adjacentRow.Value.ClearWhite); - ImGui.PopID(); + using (ImRaii.PushId($"row{id}_white")) + { + if (this.DrawColorColumn(row.ClearWhite) && adjacentRow.HasValue) + DrawEdgePreview(id, row.ClearWhite, adjacentRow.Value.ClearWhite); + } ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); - ImGui.PushID($"row{id}_green"); - if (this.DrawColorColumn(row.ClearGreen) && - adjacentRow.HasValue) - DrawEdgePreview(id, row.ClearGreen, adjacentRow.Value.ClearGreen); - ImGui.PopID(); + using (ImRaii.PushId($"row{id}_green")) + { + if (this.DrawColorColumn(row.ClearGreen) && adjacentRow.HasValue) + DrawEdgePreview(id, row.ClearGreen, adjacentRow.Value.ClearGreen); + } } } clipper.Destroy(); - ImGui.EndTable(); } private static void DrawEdgePreview(uint id, uint sheetColor, uint sheetColor2) { - ImGui.BeginTooltip(); + using var tooltip = ImRaii.Tooltip(); + Span buf = stackalloc byte[256]; var ptr = 0; ptr += Encoding.UTF8.GetBytes(" Date: Sat, 3 Jan 2026 21:09:20 +0100 Subject: [PATCH 25/99] Apply ImRaii to UldWidget --- .../Windows/Data/Widgets/UldWidget.cs | 71 ++++++++----------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs index 56ed45446..d2a195dc8 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs @@ -12,6 +12,7 @@ using Dalamud.Interface.Colors; using Dalamud.Interface.Components; using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; using Dalamud.Memory; using Lumina.Data.Files; using Lumina.Data.Parsing.Uld; @@ -159,17 +160,19 @@ internal class UldWidget : IDataWindowWidget ImGuiColors.DalamudRed, $"Error: {nameof(UldFile.AssetData)} is not populated."); } - else if (ImGui.BeginTable("##uldTextureEntries"u8, 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders)) + else { - ImGui.TableSetupColumn("Id"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("000000"u8).X); - ImGui.TableSetupColumn("Path"u8, ImGuiTableColumnFlags.WidthStretch); - ImGui.TableSetupColumn("Actions"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Preview___"u8).X); - ImGui.TableHeadersRow(); + using var table = ImRaii.Table("##uldTextureEntries"u8, 3, ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders); + if (table.Success) + { + ImGui.TableSetupColumn("Id"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("000000"u8).X); + ImGui.TableSetupColumn("Path"u8, ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupColumn("Actions"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Preview___"u8).X); + ImGui.TableHeadersRow(); - foreach (var textureEntry in uld.AssetData) - this.DrawTextureEntry(textureEntry, textureManager); - - ImGui.EndTable(); + foreach (var textureEntry in uld.AssetData) + this.DrawTextureEntry(textureEntry, textureManager); + } } } @@ -283,7 +286,7 @@ internal class UldWidget : IDataWindowWidget if (ImGui.IsItemHovered()) { - ImGui.BeginTooltip(); + using var tooltip = ImRaii.Tooltip(); var texturePath = GetStringNullTerminated(textureEntry.Path); ImGui.Text($"Base path at {texturePath}:"); @@ -301,8 +304,6 @@ internal class UldWidget : IDataWindowWidget else if (e is not null) ImGui.Text(e.ToString()); } - - ImGui.EndTooltip(); } } @@ -311,15 +312,14 @@ internal class UldWidget : IDataWindowWidget ImGui.SliderInt("FrameData"u8, ref this.selectedFrameData, 0, timeline.FrameData.Length - 1); var frameData = timeline.FrameData[this.selectedFrameData]; ImGui.Text($"FrameInfo: {frameData.StartFrame} -> {frameData.EndFrame}"); - ImGui.Indent(); + + using var indent = ImRaii.PushIndent(); foreach (var frameDataKeyGroup in frameData.KeyGroups) { ImGui.Text($"{frameDataKeyGroup.Usage:G} {frameDataKeyGroup.Type:G}"); foreach (var keyframe in frameDataKeyGroup.Frames) this.DrawTimelineKeyGroupFrame(keyframe); } - - ImGui.Unindent(); } private void DrawTimelineKeyGroupFrame(IKeyframe frame) @@ -327,8 +327,7 @@ internal class UldWidget : IDataWindowWidget switch (frame) { case BaseKeyframeData baseKeyframeData: - ImGui.Text( - $"Time: {baseKeyframeData.Time} | Interpolation: {baseKeyframeData.Interpolation} | Acceleration: {baseKeyframeData.Acceleration} | Deceleration: {baseKeyframeData.Deceleration}"); + ImGui.Text($"Time: {baseKeyframeData.Time} | Interpolation: {baseKeyframeData.Interpolation} | Acceleration: {baseKeyframeData.Acceleration} | Deceleration: {baseKeyframeData.Deceleration}"); break; case Float1Keyframe float1Keyframe: this.DrawTimelineKeyGroupFrame(float1Keyframe.Keyframe); @@ -343,8 +342,7 @@ internal class UldWidget : IDataWindowWidget case Float3Keyframe float3Keyframe: this.DrawTimelineKeyGroupFrame(float3Keyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | Value1: {float3Keyframe.Value[0]} | Value2: {float3Keyframe.Value[1]} | Value3: {float3Keyframe.Value[2]}"); + ImGui.Text($" | Value1: {float3Keyframe.Value[0]} | Value2: {float3Keyframe.Value[1]} | Value3: {float3Keyframe.Value[2]}"); break; case SByte1Keyframe sbyte1Keyframe: this.DrawTimelineKeyGroupFrame(sbyte1Keyframe.Keyframe); @@ -359,8 +357,7 @@ internal class UldWidget : IDataWindowWidget case SByte3Keyframe sbyte3Keyframe: this.DrawTimelineKeyGroupFrame(sbyte3Keyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | Value1: {sbyte3Keyframe.Value[0]} | Value2: {sbyte3Keyframe.Value[1]} | Value3: {sbyte3Keyframe.Value[2]}"); + ImGui.Text($" | Value1: {sbyte3Keyframe.Value[0]} | Value2: {sbyte3Keyframe.Value[1]} | Value3: {sbyte3Keyframe.Value[2]}"); break; case Byte1Keyframe byte1Keyframe: this.DrawTimelineKeyGroupFrame(byte1Keyframe.Keyframe); @@ -375,8 +372,7 @@ internal class UldWidget : IDataWindowWidget case Byte3Keyframe byte3Keyframe: this.DrawTimelineKeyGroupFrame(byte3Keyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | Value1: {byte3Keyframe.Value[0]} | Value2: {byte3Keyframe.Value[1]} | Value3: {byte3Keyframe.Value[2]}"); + ImGui.Text($" | Value1: {byte3Keyframe.Value[0]} | Value2: {byte3Keyframe.Value[1]} | Value3: {byte3Keyframe.Value[2]}"); break; case Short1Keyframe short1Keyframe: this.DrawTimelineKeyGroupFrame(short1Keyframe.Keyframe); @@ -391,8 +387,7 @@ internal class UldWidget : IDataWindowWidget case Short3Keyframe short3Keyframe: this.DrawTimelineKeyGroupFrame(short3Keyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | Value1: {short3Keyframe.Value[0]} | Value2: {short3Keyframe.Value[1]} | Value3: {short3Keyframe.Value[2]}"); + ImGui.Text($" | Value1: {short3Keyframe.Value[0]} | Value2: {short3Keyframe.Value[1]} | Value3: {short3Keyframe.Value[2]}"); break; case UShort1Keyframe ushort1Keyframe: this.DrawTimelineKeyGroupFrame(ushort1Keyframe.Keyframe); @@ -407,8 +402,7 @@ internal class UldWidget : IDataWindowWidget case UShort3Keyframe ushort3Keyframe: this.DrawTimelineKeyGroupFrame(ushort3Keyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | Value1: {ushort3Keyframe.Value[0]} | Value2: {ushort3Keyframe.Value[1]} | Value3: {ushort3Keyframe.Value[2]}"); + ImGui.Text($" | Value1: {ushort3Keyframe.Value[0]} | Value2: {ushort3Keyframe.Value[1]} | Value3: {ushort3Keyframe.Value[2]}"); break; case Int1Keyframe int1Keyframe: this.DrawTimelineKeyGroupFrame(int1Keyframe.Keyframe); @@ -423,8 +417,7 @@ internal class UldWidget : IDataWindowWidget case Int3Keyframe int3Keyframe: this.DrawTimelineKeyGroupFrame(int3Keyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | Value1: {int3Keyframe.Value[0]} | Value2: {int3Keyframe.Value[1]} | Value3: {int3Keyframe.Value[2]}"); + ImGui.Text($" | Value1: {int3Keyframe.Value[0]} | Value2: {int3Keyframe.Value[1]} | Value3: {int3Keyframe.Value[2]}"); break; case UInt1Keyframe uint1Keyframe: this.DrawTimelineKeyGroupFrame(uint1Keyframe.Keyframe); @@ -439,8 +432,7 @@ internal class UldWidget : IDataWindowWidget case UInt3Keyframe uint3Keyframe: this.DrawTimelineKeyGroupFrame(uint3Keyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | Value1: {uint3Keyframe.Value[0]} | Value2: {uint3Keyframe.Value[1]} | Value3: {uint3Keyframe.Value[2]}"); + ImGui.Text($" | Value1: {uint3Keyframe.Value[0]} | Value2: {uint3Keyframe.Value[1]} | Value3: {uint3Keyframe.Value[2]}"); break; case Bool1Keyframe bool1Keyframe: this.DrawTimelineKeyGroupFrame(bool1Keyframe.Keyframe); @@ -455,28 +447,22 @@ internal class UldWidget : IDataWindowWidget case Bool3Keyframe bool3Keyframe: this.DrawTimelineKeyGroupFrame(bool3Keyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | Value1: {bool3Keyframe.Value[0]} | Value2: {bool3Keyframe.Value[1]} | Value3: {bool3Keyframe.Value[2]}"); + ImGui.Text($" | Value1: {bool3Keyframe.Value[0]} | Value2: {bool3Keyframe.Value[1]} | Value3: {bool3Keyframe.Value[2]}"); break; case ColorKeyframe colorKeyframe: this.DrawTimelineKeyGroupFrame(colorKeyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | Add: {colorKeyframe.AddRed} {colorKeyframe.AddGreen} {colorKeyframe.AddBlue} | Multiply: {colorKeyframe.MultiplyRed} {colorKeyframe.MultiplyGreen} {colorKeyframe.MultiplyBlue}"); + ImGui.Text($" | Add: {colorKeyframe.AddRed} {colorKeyframe.AddGreen} {colorKeyframe.AddBlue} | Multiply: {colorKeyframe.MultiplyRed} {colorKeyframe.MultiplyGreen} {colorKeyframe.MultiplyBlue}"); break; case LabelKeyframe labelKeyframe: this.DrawTimelineKeyGroupFrame(labelKeyframe.Keyframe); ImGui.SameLine(0, 0); - ImGui.Text( - $" | LabelCommand: {labelKeyframe.LabelCommand} | JumpId: {labelKeyframe.JumpId} | LabelId: {labelKeyframe.LabelId}"); + ImGui.Text($" | LabelCommand: {labelKeyframe.LabelCommand} | JumpId: {labelKeyframe.JumpId} | LabelId: {labelKeyframe.LabelId}"); break; } } - private void DrawParts( - UldRoot.PartsData partsData, - UldRoot.TextureEntry[] textureEntries, - TextureManager textureManager) + private void DrawParts(UldRoot.PartsData partsData, UldRoot.TextureEntry[] textureEntries, TextureManager textureManager) { for (var index = 0; index < partsData.Parts.Length; index++) { @@ -542,10 +528,9 @@ internal class UldWidget : IDataWindowWidget if (ImGui.IsItemHovered()) { - ImGui.BeginTooltip(); + using var tooltip = ImRaii.Tooltip(); ImGui.Text("Click to copy:"u8); ImGui.Text(texturePath); - ImGui.EndTooltip(); } } } From 8c26d6773965eb9a927b66657e68b913d3e08e49 Mon Sep 17 00:00:00 2001 From: Infi Date: Sat, 3 Jan 2026 21:24:57 +0100 Subject: [PATCH 26/99] Apply ImRaii to TexWidget --- .../Windows/Data/Widgets/TexWidget.cs | 169 ++++++++---------- 1 file changed, 72 insertions(+), 97 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs index 3416a2506..747e18042 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs @@ -14,6 +14,7 @@ using Dalamud.Interface.Textures.Internal.SharedImmediateTextures; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Internal; +using Dalamud.Interface.Utility.Raii; using Dalamud.Plugin.Services; using Dalamud.Storage.Assets; using Dalamud.Utility; @@ -28,6 +29,10 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; ///
internal class TexWidget : IDataWindowWidget { + private const ImGuiTableFlags TableFlags = ImGuiTableFlags.Sortable | ImGuiTableFlags.SortTristate | ImGuiTableFlags.SortMulti | + ImGuiTableFlags.Reorderable | ImGuiTableFlags.Resizable | ImGuiTableFlags.NoBordersInBodyUntilResize | + ImGuiTableFlags.NoSavedSettings; + // TODO: move tracking implementation to PluginStats where applicable, // and show stats over there instead of TexWidget. private static readonly Dictionary< @@ -43,12 +48,12 @@ internal class TexWidget : IDataWindowWidget [DrawBlameTableColumnUserId.NativeAddress] = static x => x.ResourceAddress, }; - private readonly List addedTextures = new(); + private readonly List addedTextures = []; private string allLoadedTexturesTableName = "##table"; private string iconId = "18"; private bool hiRes = true; - private bool hq = false; + private bool hq; private string inputTexPath = string.Empty; private string inputFilePath = string.Empty; private Assembly[]? inputManifestResourceAssemblyCandidates; @@ -83,7 +88,7 @@ internal class TexWidget : IDataWindowWidget } /// - public string[]? CommandShortcuts { get; init; } = { "tex", "texture" }; + public string[]? CommandShortcuts { get; init; } = ["tex", "texture"]; /// public string DisplayName { get; init; } = "Tex"; @@ -140,45 +145,39 @@ internal class TexWidget : IDataWindowWidget var allBlames = this.textureManager.BlameTracker; lock (allBlames) { - ImGui.PushID("blames"u8); + using var pushedId = ImRaii.PushId("blames"u8); var sizeSum = allBlames.Sum(static x => Math.Max(0, x.RawSpecs.EstimatedBytes)); - if (ImGui.CollapsingHeader( - $"All Loaded Textures: {allBlames.Count:n0} ({Util.FormatBytes(sizeSum)})###header")) + if (ImGui.CollapsingHeader($"All Loaded Textures: {allBlames.Count:n0} ({Util.FormatBytes(sizeSum)})###header")) this.DrawBlame(allBlames); - ImGui.PopID(); } - ImGui.PushID("loadedGameTextures"u8); - if (ImGui.CollapsingHeader( - $"Loaded Game Textures: {this.textureManager.Shared.ForDebugGamePathTextures.Count:n0}###header")) - this.DrawLoadedTextures(this.textureManager.Shared.ForDebugGamePathTextures); - ImGui.PopID(); + using (ImRaii.PushId("loadedGameTextures"u8)) + { + if (ImGui.CollapsingHeader($"Loaded Game Textures: {this.textureManager.Shared.ForDebugGamePathTextures.Count:n0}###header")) + this.DrawLoadedTextures(this.textureManager.Shared.ForDebugGamePathTextures); + } - ImGui.PushID("loadedFileTextures"u8); - if (ImGui.CollapsingHeader( - $"Loaded File Textures: {this.textureManager.Shared.ForDebugFileSystemTextures.Count:n0}###header")) - this.DrawLoadedTextures(this.textureManager.Shared.ForDebugFileSystemTextures); - ImGui.PopID(); + using (ImRaii.PushId("loadedFileTextures"u8)) + { + if (ImGui.CollapsingHeader($"Loaded File Textures: {this.textureManager.Shared.ForDebugFileSystemTextures.Count:n0}###header")) + this.DrawLoadedTextures(this.textureManager.Shared.ForDebugFileSystemTextures); + } - ImGui.PushID("loadedManifestResourceTextures"u8); - if (ImGui.CollapsingHeader( - $"Loaded Manifest Resource Textures: {this.textureManager.Shared.ForDebugManifestResourceTextures.Count:n0}###header")) - this.DrawLoadedTextures(this.textureManager.Shared.ForDebugManifestResourceTextures); - ImGui.PopID(); + using (ImRaii.PushId("loadedManifestResourceTextures"u8)) + { + if (ImGui.CollapsingHeader($"Loaded Manifest Resource Textures: {this.textureManager.Shared.ForDebugManifestResourceTextures.Count:n0}###header")) + this.DrawLoadedTextures(this.textureManager.Shared.ForDebugManifestResourceTextures); + } lock (this.textureManager.Shared.ForDebugInvalidatedTextures) { - ImGui.PushID("invalidatedTextures"u8); - if (ImGui.CollapsingHeader( - $"Invalidated: {this.textureManager.Shared.ForDebugInvalidatedTextures.Count:n0}###header")) - { + using var pushedId = ImRaii.PushId("invalidatedTextures"u8); + if (ImGui.CollapsingHeader($"Invalidated: {this.textureManager.Shared.ForDebugInvalidatedTextures.Count:n0}###header")) this.DrawLoadedTextures(this.textureManager.Shared.ForDebugInvalidatedTextures); - } - - ImGui.PopID(); } - ImGui.Dummy(new(ImGui.GetTextLineHeightWithSpacing())); + var textHeightSpacing = new Vector2(ImGui.GetTextLineHeightWithSpacing()); + ImGui.Dummy(textHeightSpacing); if (!this.textureManager.HasClipboardImage()) { @@ -191,59 +190,53 @@ internal class TexWidget : IDataWindowWidget if (ImGui.CollapsingHeader(nameof(ITextureProvider.GetFromGameIcon))) { - ImGui.PushID(nameof(this.DrawGetFromGameIcon)); + using var pushedId = ImRaii.PushId(nameof(this.DrawGetFromGameIcon)); this.DrawGetFromGameIcon(); - ImGui.PopID(); } if (ImGui.CollapsingHeader(nameof(ITextureProvider.GetFromGame))) { - ImGui.PushID(nameof(this.DrawGetFromGame)); + using var pushedId = ImRaii.PushId(nameof(this.DrawGetFromGame)); this.DrawGetFromGame(); - ImGui.PopID(); } if (ImGui.CollapsingHeader(nameof(ITextureProvider.GetFromFile))) { - ImGui.PushID(nameof(this.DrawGetFromFile)); + using var pushedId = ImRaii.PushId(nameof(this.DrawGetFromFile)); this.DrawGetFromFile(); - ImGui.PopID(); } if (ImGui.CollapsingHeader(nameof(ITextureProvider.GetFromManifestResource))) { - ImGui.PushID(nameof(this.DrawGetFromManifestResource)); + using var pushedId = ImRaii.PushId(nameof(this.DrawGetFromManifestResource)); this.DrawGetFromManifestResource(); - ImGui.PopID(); } if (ImGui.CollapsingHeader(nameof(ITextureProvider.CreateFromImGuiViewportAsync))) { - ImGui.PushID(nameof(this.DrawCreateFromImGuiViewportAsync)); + using var pushedId = ImRaii.PushId(nameof(this.DrawCreateFromImGuiViewportAsync)); this.DrawCreateFromImGuiViewportAsync(); - ImGui.PopID(); } if (ImGui.CollapsingHeader("UV"u8)) { - ImGui.PushID(nameof(this.DrawUvInput)); + using var pushedId = ImRaii.PushId(nameof(this.DrawUvInput)); this.DrawUvInput(); - ImGui.PopID(); } if (ImGui.CollapsingHeader($"CropCopy##{nameof(this.DrawExistingTextureModificationArgs)}")) { - ImGui.PushID(nameof(this.DrawExistingTextureModificationArgs)); + using var pushedId = ImRaii.PushId(nameof(this.DrawExistingTextureModificationArgs)); this.DrawExistingTextureModificationArgs(); - ImGui.PopID(); } - ImGui.Dummy(new(ImGui.GetTextLineHeightWithSpacing())); + ImGui.Dummy(textHeightSpacing); Action? runLater = null; foreach (var t in this.addedTextures) { - ImGui.PushID(t.Id); + using var pushedId = ImRaii.PushId(t.Id); + if (ImGui.CollapsingHeader($"Tex #{t.Id} {t}###header", ImGuiTreeNodeFlags.DefaultOpen)) { if (ImGui.Button("X"u8)) @@ -335,8 +328,6 @@ internal class TexWidget : IDataWindowWidget ImGui.Text(e.ToString()); } } - - ImGui.PopID(); } runLater?.Invoke(); @@ -356,18 +347,16 @@ internal class TexWidget : IDataWindowWidget if (ImGui.Button("Reset Columns"u8)) this.allLoadedTexturesTableName = "##table" + Environment.TickCount64; - if (!ImGui.BeginTable( - this.allLoadedTexturesTableName, - (int)DrawBlameTableColumnUserId.ColumnCount, - ImGuiTableFlags.Sortable | ImGuiTableFlags.SortTristate | ImGuiTableFlags.SortMulti | - ImGuiTableFlags.Reorderable | ImGuiTableFlags.Resizable | ImGuiTableFlags.NoBordersInBodyUntilResize | - ImGuiTableFlags.NoSavedSettings)) + using var table = ImRaii.Table(this.allLoadedTexturesTableName, (int)DrawBlameTableColumnUserId.ColumnCount, TableFlags); + if (!table.Success) return; const int numIcons = 1; float iconWidths; using (im.IconFontHandle?.Push()) + { iconWidths = ImGui.CalcTextSize(FontAwesomeIcon.Save.ToIconString()).X; + } ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableSetupColumn( @@ -462,7 +451,8 @@ internal class TexWidget : IDataWindowWidget { var wrap = allBlames[i]; ImGui.TableNextRow(); - ImGui.PushID(i); + + using var pushedId = ImRaii.PushId(i); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); @@ -479,9 +469,8 @@ internal class TexWidget : IDataWindowWidget if (ImGui.IsItemHovered()) { - ImGui.BeginTooltip(); + using var tooltip = ImRaii.Tooltip(); ImGui.Image(wrap.Handle, wrap.Size); - ImGui.EndTooltip(); } ImGui.TableNextColumn(); @@ -503,21 +492,19 @@ internal class TexWidget : IDataWindowWidget ImGui.TableNextColumn(); lock (wrap.OwnerPlugins) this.TextColumnCopiable(string.Join(", ", wrap.OwnerPlugins.Select(static x => x.Name)), false, true); - - ImGui.PopID(); } } clipper.Destroy(); - ImGui.EndTable(); ImGuiHelpers.ScaledDummy(10); } - private unsafe void DrawLoadedTextures(ICollection textures) + private void DrawLoadedTextures(ICollection textures) { var im = Service.Get(); - if (!ImGui.BeginTable("##table"u8, 6)) + using var table = ImRaii.Table("##table"u8, 6); + if (!table.Success) return; const int numIcons = 4; @@ -575,7 +562,7 @@ internal class TexWidget : IDataWindowWidget } var remain = texture.SelfReferenceExpiresInForDebug; - ImGui.PushID(row); + using var pushedId = ImRaii.PushId(row); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); @@ -602,28 +589,26 @@ internal class TexWidget : IDataWindowWidget if (ImGui.IsItemHovered() && texture.GetWrapOrDefault(null) is { } immediate) { - ImGui.BeginTooltip(); + using var tooltip = ImRaii.Tooltip(); ImGui.Image(immediate.Handle, immediate.Size); - ImGui.EndTooltip(); } ImGui.SameLine(); if (ImGuiComponents.IconButton(FontAwesomeIcon.Sync)) - this.textureManager.InvalidatePaths(new[] { texture.SourcePathForDebug }); + this.textureManager.InvalidatePaths([texture.SourcePathForDebug]); + if (ImGui.IsItemHovered()) ImGui.SetTooltip($"Call {nameof(ITextureSubstitutionProvider.InvalidatePaths)}."); ImGui.SameLine(); - if (remain <= 0) - ImGui.BeginDisabled(); - if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) - texture.ReleaseSelfReference(true); - if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) - ImGui.SetTooltip("Release self-reference immediately."u8); - if (remain <= 0) - ImGui.EndDisabled(); + using (ImRaii.Disabled(remain <= 0)) + { + if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash)) + texture.ReleaseSelfReference(true); - ImGui.PopID(); + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) + ImGui.SetTooltip("Release self-reference immediately."u8); + } } if (!valid) @@ -632,7 +617,6 @@ internal class TexWidget : IDataWindowWidget } clipper.Destroy(); - ImGui.EndTable(); ImGuiHelpers.ScaledDummy(10); } @@ -751,10 +735,7 @@ internal class TexWidget : IDataWindowWidget { ImGui.SameLine(); if (ImGui.Button("Load File (Async)"u8)) - { - this.addedTextures.Add( - new(Api10: this.textureManager.Shared.GetFromManifestResource(assembly, name).RentAsync())); - } + this.addedTextures.Add(new(Api10: this.textureManager.Shared.GetFromManifestResource(assembly, name).RentAsync())); ImGui.SameLine(); if (ImGui.Button("Load File (Immediate)"u8)) @@ -767,21 +748,20 @@ internal class TexWidget : IDataWindowWidget private void DrawCreateFromImGuiViewportAsync() { var viewports = ImGui.GetPlatformIO().Viewports; - if (ImGui.BeginCombo( - nameof(this.viewportTextureArgs.ViewportId), - $"{this.viewportIndexInt}. {viewports[this.viewportIndexInt].ID:X08}")) + using (var combo = ImRaii.Combo(nameof(this.viewportTextureArgs.ViewportId), $"{this.viewportIndexInt}. {viewports[this.viewportIndexInt].ID:X08}")) { - for (var i = 0; i < viewports.Size; i++) + if (combo.Success) { - var sel = this.viewportIndexInt == i; - if (ImGui.Selectable($"#{i}: {viewports[i].ID:X08}", ref sel)) + for (var i = 0; i < viewports.Size; i++) { - this.viewportIndexInt = i; - ImGui.SetItemDefaultFocus(); + var sel = this.viewportIndexInt == i; + if (ImGui.Selectable($"#{i}: {viewports[i].ID:X08}", ref sel)) + { + this.viewportIndexInt = i; + ImGui.SetItemDefaultFocus(); + } } } - - ImGui.EndCombo(); } var b = this.viewportTextureArgs.KeepTransparency; @@ -843,17 +823,12 @@ internal class TexWidget : IDataWindowWidget } this.supportedRenderTargetFormatNames ??= this.supportedRenderTargetFormats.Select(Enum.GetName).ToArray(); - ImGui.Combo( - nameof(this.textureModificationArgs.DxgiFormat), - ref this.renderTargetChoiceInt, - this.supportedRenderTargetFormatNames); + ImGui.Combo(nameof(this.textureModificationArgs.DxgiFormat), ref this.renderTargetChoiceInt, this.supportedRenderTargetFormatNames); Span wh = stackalloc int[2]; wh[0] = this.textureModificationArgs.NewWidth; wh[1] = this.textureModificationArgs.NewHeight; - if (ImGui.InputInt( - $"{nameof(this.textureModificationArgs.NewWidth)}/{nameof(this.textureModificationArgs.NewHeight)}", - wh)) + if (ImGui.InputInt($"{nameof(this.textureModificationArgs.NewWidth)}/{nameof(this.textureModificationArgs.NewHeight)}", wh)) { this.textureModificationArgs.NewWidth = wh[0]; this.textureModificationArgs.NewHeight = wh[1]; From 5fe6df38876b289c70a39d7726cea131f8c8ae3b Mon Sep 17 00:00:00 2001 From: Infi Date: Sat, 3 Jan 2026 21:31:28 +0100 Subject: [PATCH 27/99] Cleanup TaskSchedulerWidget and ensure color is always popped --- .../Data/Widgets/TaskSchedulerWidget.cs | 45 +++++++------------ 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/TaskSchedulerWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/TaskSchedulerWidget.cs index cd72d751e..bf838623c 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/TaskSchedulerWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/TaskSchedulerWidget.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Net.Http; using System.Reflection; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -35,7 +34,7 @@ internal class TaskSchedulerWidget : IDataWindowWidget private CancellationTokenSource taskSchedulerCancelSource = new(); /// - public string[]? CommandShortcuts { get; init; } = { "tasksched", "taskscheduler" }; + public string[]? CommandShortcuts { get; init; } = ["tasksched", "taskscheduler"]; /// public string DisplayName { get; init; } = "Task Scheduler"; @@ -266,8 +265,7 @@ internal class TaskSchedulerWidget : IDataWindowWidget ImGui.Text($"{this.downloadState.Downloaded:##,###}/{this.downloadState.Total:##,###} ({this.downloadState.Percentage:0.00}%)"); - using var disabled = - ImRaii.Disabled(this.downloadTask?.IsCompleted is false || this.localPath[0] == 0); + using var disabled = ImRaii.Disabled(this.downloadTask?.IsCompleted is false || this.localPath[0] == 0); ImGui.AlignTextToFramePadding(); ImGui.Text("Download"u8); ImGui.SameLine(); @@ -388,27 +386,19 @@ internal class TaskSchedulerWidget : IDataWindowWidget if (task.Task == null) subTime = task.FinishTime; - switch (task.Status) + using var pushedColor = task.Status switch { - case TaskStatus.Created: - case TaskStatus.WaitingForActivation: - case TaskStatus.WaitingToRun: - ImGui.PushStyleColor(ImGuiCol.Header, ImGuiColors.DalamudGrey); - break; - case TaskStatus.Running: - case TaskStatus.WaitingForChildrenToComplete: - ImGui.PushStyleColor(ImGuiCol.Header, ImGuiColors.ParsedBlue); - break; - case TaskStatus.RanToCompletion: - ImGui.PushStyleColor(ImGuiCol.Header, ImGuiColors.ParsedGreen); - break; - case TaskStatus.Canceled: - case TaskStatus.Faulted: - ImGui.PushStyleColor(ImGuiCol.Header, ImGuiColors.DalamudRed); - break; - default: - throw new ArgumentOutOfRangeException(); - } + TaskStatus.Created or TaskStatus.WaitingForActivation or TaskStatus.WaitingToRun + => ImRaii.PushColor(ImGuiCol.Header, ImGuiColors.DalamudGrey), + TaskStatus.Running or TaskStatus.WaitingForChildrenToComplete + => ImRaii.PushColor(ImGuiCol.Header, ImGuiColors.ParsedBlue), + TaskStatus.RanToCompletion + => ImRaii.PushColor(ImGuiCol.Header, ImGuiColors.ParsedGreen), + TaskStatus.Canceled or TaskStatus.Faulted + => ImRaii.PushColor(ImGuiCol.Header, ImGuiColors.DalamudRed), + + _ => throw new ArgumentOutOfRangeException(), + }; if (ImGui.CollapsingHeader($"#{task.Id} - {task.Status} {(subTime - task.StartTime).TotalMilliseconds}ms###task{i}")) { @@ -418,8 +408,7 @@ internal class TaskSchedulerWidget : IDataWindowWidget { try { - var cancelFunc = - typeof(Task).GetMethod("InternalCancel", BindingFlags.NonPublic | BindingFlags.Instance); + var cancelFunc = typeof(Task).GetMethod("InternalCancel", BindingFlags.NonPublic | BindingFlags.Instance); cancelFunc?.Invoke(task, null); } catch (Exception ex) @@ -430,7 +419,7 @@ internal class TaskSchedulerWidget : IDataWindowWidget ImGuiHelpers.ScaledDummy(10); - ImGui.Text(task.StackTrace?.ToString()); + ImGui.Text(task.StackTrace?.ToString() ?? "Null StackTrace"); if (task.Exception != null) { @@ -443,8 +432,6 @@ internal class TaskSchedulerWidget : IDataWindowWidget { task.IsBeingViewed = false; } - - ImGui.PopStyleColor(1); } this.fileDialogManager.Draw(); From 09a1fd19255beb34a77f1b4123be9affacb510c0 Mon Sep 17 00:00:00 2001 From: Infi Date: Sat, 3 Jan 2026 21:43:12 +0100 Subject: [PATCH 28/99] - Apply ImRaii to SeStringRendererTestWidget - Add new themes - Remove uses of Dalamud SeString - Use collection expression --- .../Widgets/SeStringRendererTestWidget.cs | 34 ++++++++----------- .../Windows/Data/Widgets/StartInfoWidget.cs | 2 +- .../Windows/Data/Widgets/TargetWidget.cs | 2 +- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs index 6a07152e5..958f9d037 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs @@ -11,6 +11,7 @@ using Dalamud.Interface.ImGuiSeStringRenderer.Internal; using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Internal; +using Dalamud.Interface.Utility.Raii; using Dalamud.Storage.Assets; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -27,7 +28,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal unsafe class SeStringRendererTestWidget : IDataWindowWidget { - private static readonly string[] ThemeNames = ["Dark", "Light", "Classic FF", "Clear Blue"]; + private static readonly string[] ThemeNames = ["Dark", "Light", "Classic FF", "Clear Blue", "Clear White", "Clear Green"]; private ImVectorWrapper testStringBuffer; private string testString = string.Empty; private ReadOnlySeString? logkind; @@ -117,9 +118,11 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget ImGui.SameLine(); var t4 = this.style.ThemeIndex ?? AtkStage.Instance()->AtkUIColorHolder->ActiveColorThemeType; - ImGui.PushItemWidth(ImGui.CalcTextSize("WWWWWWWWWWWWWW"u8).X); - if (ImGui.Combo("##theme", ref t4, ThemeNames)) - this.style.ThemeIndex = t4; + using (ImRaii.ItemWidth(ImGui.CalcTextSize("WWWWWWWWWWWWWW"u8).X)) + { + if (ImGui.Combo("##theme", ref t4, ThemeNames)) + this.style.ThemeIndex = t4; + } ImGui.SameLine(); t = this.style.LinkUnderlineThickness > 0f; @@ -190,22 +193,19 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget dl.PushClipRect(clipMin, clipMax); ImGuiHelpers.CompileSeStringWrapped( "Test test", - new SeStringDrawParams - { Color = 0xFFFFFFFF, WrapWidth = float.MaxValue, TargetDrawList = dl }); + new SeStringDrawParams { Color = 0xFFFFFFFF, WrapWidth = float.MaxValue, TargetDrawList = dl }); dl.PopClipRect(); } if (ImGui.CollapsingHeader("Addon Table"u8)) { - if (ImGui.BeginTable("Addon Sheet"u8, 3)) + using var table = ImRaii.Table("Addon Sheet"u8, 3); + if (table.Success) { ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableSetupColumn("Row ID"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("0000000"u8).X); ImGui.TableSetupColumn("Text"u8, ImGuiTableColumnFlags.WidthStretch); - ImGui.TableSetupColumn( - "Misc"u8, - ImGuiTableColumnFlags.WidthFixed, - ImGui.CalcTextSize("AAAAAAAAAAAAAAAAA"u8).X); + ImGui.TableSetupColumn("Misc"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("AAAAAAAAAAAAAAAAA"u8).X); ImGui.TableHeadersRow(); var addon = Service.GetNullable()?.GetExcelSheet() ?? @@ -220,7 +220,7 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget var row = addon.GetRowAt(i); ImGui.TableNextRow(); - ImGui.PushID(i); + using var pushedId = ImRaii.PushId(i); ImGui.TableNextColumn(); ImGui.AlignTextToFramePadding(); @@ -232,14 +232,11 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget ImGui.TableNextColumn(); if (ImGui.Button("Print to Chat"u8)) - Service.Get().Print(row.Text.ToDalamudString()); - - ImGui.PopID(); + Service.Get().Print(row.Text); } } clipper.Destroy(); - ImGui.EndTable(); } } @@ -256,9 +253,7 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget if (ImGui.Button("Print to Chat Log"u8)) { - Service.Get().Print( - Game.Text.SeStringHandling.SeString.Parse( - Service.Get().CompileAndCache(this.testString).Data.Span)); + Service.Get().Print(Service.Get().CompileAndCache(this.testString)); } ImGui.SameLine(); @@ -313,6 +308,7 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget var len = this.testStringBuffer.StorageSpan.IndexOf((byte)0); if (len + 4 >= this.testStringBuffer.Capacity) this.testStringBuffer.EnsureCapacityExponential(len + 4); + if (len < this.testStringBuffer.Capacity) { this.testStringBuffer.LengthUnsafe = len; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/StartInfoWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/StartInfoWidget.cs index 7fb2cc2bf..4f71973c8 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/StartInfoWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/StartInfoWidget.cs @@ -9,7 +9,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class StartInfoWidget : IDataWindowWidget { /// - public string[]? CommandShortcuts { get; init; } = { "startinfo" }; + public string[]? CommandShortcuts { get; init; } = ["startinfo"]; /// public string DisplayName { get; init; } = "Start Info"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/TargetWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/TargetWidget.cs index 6caf3286d..2e52d7586 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/TargetWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/TargetWidget.cs @@ -14,7 +14,7 @@ internal class TargetWidget : IDataWindowWidget private bool resolveGameData; /// - public string[]? CommandShortcuts { get; init; } = { "target" }; + public string[]? CommandShortcuts { get; init; } = ["target"]; /// public string DisplayName { get; init; } = "Target"; From 9b55b020ca32b0482b1306aebbbd6701ccd5fd47 Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Sat, 3 Jan 2026 23:11:50 +0100 Subject: [PATCH 29/99] Switch selftest to using mounts instead of teleporting --- .../SelfTest/Steps/ChatSelfTestStep.cs | 54 +++++++++---------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs index 16fd3b01e..73f0405ef 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs @@ -1,10 +1,13 @@ using Dalamud.Bindings.ImGui; +using Dalamud.Data; using Dalamud.Game.Chat; using Dalamud.Game.Gui; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.SelfTest; +using Lumina.Excel.Sheets; + namespace Dalamud.Interface.Internal.Windows.SelfTest.Steps; /// @@ -15,10 +18,10 @@ internal class ChatSelfTestStep : ISelfTestStep private int step = 0; private bool subscribedChatMessage = false; private bool subscribedLogMessage = false; - private bool hasPassed = false; - private bool hasTeleportGil = false; - private bool hasTeleportTicket = false; - private int teleportCount = 0; + private bool hasSeenEchoMessage = false; + private bool hasSeenMountMessage = false; + private string mountName = ""; + private string mountUser = ""; /// public string Name => "Test Chat"; @@ -45,7 +48,7 @@ internal class ChatSelfTestStep : ISelfTestStep chatGui.ChatMessage += this.ChatOnOnChatMessage; } - if (this.hasPassed) + if (this.hasSeenEchoMessage) { chatGui.ChatMessage -= this.ChatOnOnChatMessage; this.subscribedChatMessage = false; @@ -55,7 +58,7 @@ internal class ChatSelfTestStep : ISelfTestStep break; case 2: - ImGui.Text("Teleport somewhere..."); + ImGui.Text("Use any mount..."); if (!this.subscribedLogMessage) { @@ -63,18 +66,11 @@ internal class ChatSelfTestStep : ISelfTestStep chatGui.LogMessage += this.ChatOnLogMessage; } - if (this.hasTeleportGil) + if (this.hasSeenMountMessage) { - ImGui.Text($"You spent {this.teleportCount} gil to teleport."); - } - if (this.hasTeleportTicket) - { - ImGui.Text($"You used a ticket to teleport and have {this.teleportCount} remaining."); - } - - if (this.hasTeleportGil || this.hasTeleportTicket) - { - ImGui.Text("Is this correct?"); + ImGui.Text($"{this.mountUser} mounted {this.mountName}."); + + ImGui.Text("Is this correct? It is correct if this triggers on other players around you."); if (ImGui.Button("Yes")) { @@ -117,23 +113,25 @@ internal class ChatSelfTestStep : ISelfTestStep { if (type == XivChatType.Echo && message.TextValue == "DALAMUD") { - this.hasPassed = true; + this.hasSeenEchoMessage = true; } } private void ChatOnLogMessage(ILogMessage message) { - if (message.LogMessageId == 4590 && message.TryGetIntParameter(0, out var value)) + if (message.LogMessageId == 646 && message.TryGetIntParameter(0, out var value)) { - this.hasTeleportGil = true; - this.hasTeleportTicket = false; - this.teleportCount = value; - } - if (message.LogMessageId == 4591 && message.TryGetIntParameter(0, out var item) && item == 7569 && message.TryGetIntParameter(1, out var remaining)) - { - this.hasTeleportGil = false; - this.hasTeleportTicket = true; - this.teleportCount = remaining; + this.hasSeenMountMessage = true; + this.mountUser = message.SourceEntity?.Name.ExtractText() ?? ""; + try + { + this.mountName = Service.Get().GetExcelSheet().GetRow((uint)value).Singular.ExtractText(); + } + catch + { + // ignore any errors with retrieving the mount name, they are probably not related to this test + this.mountName = $"Mount ID: {value} (failed to retrieve mount name)"; + } } } } From 790669e60abdc32e49e59c65315950340140b1a3 Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Sun, 4 Jan 2026 08:12:06 +0100 Subject: [PATCH 30/99] Battle log exists, selftest with the use action message --- .../SelfTest/Steps/ChatSelfTestStep.cs | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs index 73f0405ef..d4311176e 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs @@ -1,13 +1,10 @@ using Dalamud.Bindings.ImGui; -using Dalamud.Data; using Dalamud.Game.Chat; using Dalamud.Game.Gui; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.SelfTest; -using Lumina.Excel.Sheets; - namespace Dalamud.Interface.Internal.Windows.SelfTest.Steps; /// @@ -19,9 +16,9 @@ internal class ChatSelfTestStep : ISelfTestStep private bool subscribedChatMessage = false; private bool subscribedLogMessage = false; private bool hasSeenEchoMessage = false; - private bool hasSeenMountMessage = false; - private string mountName = ""; - private string mountUser = ""; + private bool hasSeenActionMessage = false; + private string actionName = ""; + private string actionUser = ""; /// public string Name => "Test Chat"; @@ -58,7 +55,7 @@ internal class ChatSelfTestStep : ISelfTestStep break; case 2: - ImGui.Text("Use any mount..."); + ImGui.Text("Use any action (for example Sprint) or be near a player using an action."); if (!this.subscribedLogMessage) { @@ -66,11 +63,10 @@ internal class ChatSelfTestStep : ISelfTestStep chatGui.LogMessage += this.ChatOnLogMessage; } - if (this.hasSeenMountMessage) + if (this.hasSeenActionMessage) { - ImGui.Text($"{this.mountUser} mounted {this.mountName}."); - - ImGui.Text("Is this correct? It is correct if this triggers on other players around you."); + ImGui.Text($"{this.actionUser} used {this.actionName}."); + ImGui.Text("Is this correct?"); if (ImGui.Button("Yes")) { @@ -119,19 +115,11 @@ internal class ChatSelfTestStep : ISelfTestStep private void ChatOnLogMessage(ILogMessage message) { - if (message.LogMessageId == 646 && message.TryGetIntParameter(0, out var value)) + if (message.LogMessageId == 533 && message.TryGetStringParameter(0, out var value)) { - this.hasSeenMountMessage = true; - this.mountUser = message.SourceEntity?.Name.ExtractText() ?? ""; - try - { - this.mountName = Service.Get().GetExcelSheet().GetRow((uint)value).Singular.ExtractText(); - } - catch - { - // ignore any errors with retrieving the mount name, they are probably not related to this test - this.mountName = $"Mount ID: {value} (failed to retrieve mount name)"; - } + this.hasSeenActionMessage = true; + this.actionUser = message.SourceEntity?.Name.ExtractText() ?? ""; + this.actionName = value.ExtractText(); } } } From 6e19aca481a9c49ea0a46b94bdc8671c230f3f82 Mon Sep 17 00:00:00 2001 From: RedworkDE <10944644+RedworkDE@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:00:10 +0100 Subject: [PATCH 31/99] Fix StyleCop warnings --- Dalamud/Game/Chat/LogMessage.cs | 75 ++++++++++--------- Dalamud/Game/Chat/LogMessageEntity.cs | 48 ++++++++---- .../SelfTest/Steps/ChatSelfTestStep.cs | 4 +- Dalamud/Plugin/Services/IChatGui.cs | 1 - 4 files changed, 72 insertions(+), 56 deletions(-) diff --git a/Dalamud/Game/Chat/LogMessage.cs b/Dalamud/Game/Chat/LogMessage.cs index 93b928d48..c772783a1 100644 --- a/Dalamud/Game/Chat/LogMessage.cs +++ b/Dalamud/Game/Chat/LogMessage.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + using Dalamud.Data; using Dalamud.Utility; @@ -10,8 +12,6 @@ using FFXIVClientStructs.Interop; using Lumina.Excel; using Lumina.Text.ReadOnly; -using System.Diagnostics.CodeAnalysis; - namespace Dalamud.Game.Chat; /// @@ -88,30 +88,41 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa /// public RowRef GameData => LuminaUtils.CreateRef(ptr->LogMessageId); - public LogMessageEntity SourceEntity => new LogMessageEntity(ptr, true); /// ILogMessageEntity? ILogMessage.SourceEntity => ptr->SourceKind == EntityRelationKind.None ? null : this.SourceEntity; - public LogMessageEntity TargetEntity => new LogMessageEntity(ptr, false); - /// ILogMessageEntity? ILogMessage.TargetEntity => ptr->TargetKind == EntityRelationKind.None ? null : this.TargetEntity; /// public int ParameterCount => ptr->Parameters.Count; - public bool TryGetParameter(int index, out TextParameter value) - { - if (index < 0 || index >= ptr->Parameters.Count) - { - value = default; - return false; - } + private LogMessageEntity SourceEntity => new(ptr, true); - value = ptr->Parameters[index]; - return true; + private LogMessageEntity TargetEntity => new(ptr, false); + + public static bool operator ==(LogMessage x, LogMessage y) => x.Equals(y); + + public static bool operator !=(LogMessage x, LogMessage y) => !(x == y); + + /// + public bool Equals(ILogMessage? other) + { + return other is LogMessage logMessage && this.Equals(logMessage); } + /// + public override bool Equals([NotNullWhen(true)] object? obj) + { + return obj is LogMessage logMessage && this.Equals(logMessage); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(this.LogMessageId, this.SourceEntity, this.TargetEntity); + } + /// public bool TryGetIntParameter(int index, out int value) { @@ -132,6 +143,7 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa value = new(parameter.StringValue.AsSpan()); return true; } + if (parameter.Type == TextParameterType.ReferencedUtf8String) { value = new(parameter.ReferencedUtf8StringValue->Utf8String.AsSpan()); @@ -157,7 +169,7 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa return new ReadOnlySeString(utf8.AsSpan()); - void SetName(RaptureLogModule* self, LogMessageEntity item) + static void SetName(RaptureLogModule* self, LogMessageEntity item) { var name = item.NameSpan.GetPointer(0); @@ -190,31 +202,20 @@ internal unsafe readonly struct LogMessage(LogMessageQueueItem* ptr) : ILogMessa } } + private bool TryGetParameter(int index, out TextParameter value) + { + if (index < 0 || index >= ptr->Parameters.Count) + { + value = default; + return false; + } - public static bool operator ==(LogMessage x, LogMessage y) => x.Equals(y); + value = ptr->Parameters[index]; + return true; + } - public static bool operator !=(LogMessage x, LogMessage y) => !(x == y); - - public bool Equals(LogMessage other) + private bool Equals(LogMessage other) { return this.LogMessageId == other.LogMessageId && this.SourceEntity == other.SourceEntity && this.TargetEntity == other.TargetEntity; } - - /// - public bool Equals(ILogMessage? other) - { - return other is LogMessage logMessage && this.Equals(logMessage); - } - - /// - public override bool Equals([NotNullWhen(true)] object? obj) - { - return obj is LogMessage logMessage && this.Equals(logMessage); - } - - /// - public override int GetHashCode() - { - return HashCode.Combine(this.LogMessageId, this.SourceEntity, this.TargetEntity); - } } diff --git a/Dalamud/Game/Chat/LogMessageEntity.cs b/Dalamud/Game/Chat/LogMessageEntity.cs index 4294e4898..91e905928 100644 --- a/Dalamud/Game/Chat/LogMessageEntity.cs +++ b/Dalamud/Game/Chat/LogMessageEntity.cs @@ -37,46 +37,57 @@ public interface ILogMessageEntity : IEquatable uint ObjStrId { get; } /// - /// Gets a boolean indicating if this entity is a player. + /// Gets a value indicating whether this entity is a player. /// bool IsPlayer { get; } } - /// /// This struct represents an entity related to a log message. /// /// A pointer to the log message item. -/// If represents the source entity of the log message, otherwise represents the target entity +/// If represents the source entity of the log message, otherwise represents the target entity. internal unsafe readonly struct LogMessageEntity(LogMessageQueueItem* ptr, bool source) : ILogMessageEntity { - public Span NameSpan => source ? ptr->SourceName : ptr->TargetName; - - public ReadOnlySeString Name => new ReadOnlySeString(this.NameSpan[..this.NameSpan.IndexOf((byte)0)]); + /// + public ReadOnlySeString Name => new(this.NameSpan[..this.NameSpan.IndexOf((byte)0)]); + /// public ushort HomeWorldId => source ? ptr->SourceHomeWorld : ptr->TargetHomeWorld; + /// public RowRef HomeWorld => LuminaUtils.CreateRef(this.HomeWorldId); + /// public uint ObjStrId => source ? ptr->SourceObjStrId : ptr->TargetObjStrId; - public byte Kind => source ? (byte)ptr->SourceKind : (byte)ptr->TargetKind; - - public byte Sex => source ? ptr->SourceSex : ptr->TargetSex; - + /// public bool IsPlayer => source ? ptr->SourceIsPlayer : ptr->TargetIsPlayer; - public bool IsSourceEntity => source; + /// + /// Gets the Span containing the raw name of this entity. + /// + internal Span NameSpan => source ? ptr->SourceName : ptr->TargetName; + + /// + /// Gets the kind of the entity. + /// + internal byte Kind => source ? (byte)ptr->SourceKind : (byte)ptr->TargetKind; + + /// + /// Gets the Sex of this entity. + /// + internal byte Sex => source ? ptr->SourceSex : ptr->TargetSex; + + /// + /// Gets a value indicating whether this entity is the source entity of a log message. + /// + internal bool IsSourceEntity => source; public static bool operator ==(LogMessageEntity x, LogMessageEntity y) => x.Equals(y); public static bool operator !=(LogMessageEntity x, LogMessageEntity y) => !(x == y); - public bool Equals(LogMessageEntity other) - { - return this.Name == other.Name && this.HomeWorldId == other.HomeWorldId && this.ObjStrId == other.ObjStrId && this.Kind == other.Kind && this.Sex == other.Sex && this.IsPlayer == other.IsPlayer; - } - /// public bool Equals(ILogMessageEntity other) { @@ -94,4 +105,9 @@ internal unsafe readonly struct LogMessageEntity(LogMessageQueueItem* ptr, bool { return HashCode.Combine(this.Name, this.HomeWorldId, this.ObjStrId, this.Sex, this.IsPlayer); } + + private bool Equals(LogMessageEntity other) + { + return this.Name == other.Name && this.HomeWorldId == other.HomeWorldId && this.ObjStrId == other.ObjStrId && this.Kind == other.Kind && this.Sex == other.Sex && this.IsPlayer == other.IsPlayer; + } } diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs index d4311176e..851957b4b 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ChatSelfTestStep.cs @@ -17,8 +17,8 @@ internal class ChatSelfTestStep : ISelfTestStep private bool subscribedLogMessage = false; private bool hasSeenEchoMessage = false; private bool hasSeenActionMessage = false; - private string actionName = ""; - private string actionUser = ""; + private string actionName = string.Empty; + private string actionUser = string.Empty; /// public string Name => "Test Chat"; diff --git a/Dalamud/Plugin/Services/IChatGui.cs b/Dalamud/Plugin/Services/IChatGui.cs index eec25cb5a..2bb7b6913 100644 --- a/Dalamud/Plugin/Services/IChatGui.cs +++ b/Dalamud/Plugin/Services/IChatGui.cs @@ -51,7 +51,6 @@ public interface IChatGui : IDalamudService /// The message sent. public delegate void OnMessageUnhandledDelegate(XivChatType type, int timestamp, SeString sender, SeString message); - /// /// A delegate type used with the event. /// From 13980542168073087f38cf6da09516d8aa0d8ced Mon Sep 17 00:00:00 2001 From: MidoriKami Date: Sun, 4 Jan 2026 14:03:15 -0800 Subject: [PATCH 32/99] Push AddonLifecycle event register/unregister to main thread --- .../Game/Addon/Lifecycle/AddonLifecycle.cs | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs b/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs index 78cea1a0f..4da8e429c 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs @@ -27,6 +27,9 @@ internal unsafe class AddonLifecycle : IInternalDisposableService private static readonly ModuleLog Log = new("AddonLifecycle"); + [ServiceManager.ServiceDependency] + private readonly Framework framework = Service.Get(); + private Hook? onInitializeAddonHook; [ServiceManager.ServiceConstructor] @@ -58,20 +61,23 @@ internal unsafe class AddonLifecycle : IInternalDisposableService /// The listener to register. internal void RegisterListener(AddonLifecycleEventListener listener) { - if (!this.EventListeners.ContainsKey(listener.EventType)) + this.framework.RunOnFrameworkThread(() => { - if (!this.EventListeners.TryAdd(listener.EventType, [])) - return; - } + if (!this.EventListeners.ContainsKey(listener.EventType)) + { + if (!this.EventListeners.TryAdd(listener.EventType, [])) + return; + } - // Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type - if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName)) - { - if (!this.EventListeners[listener.EventType].TryAdd(listener.AddonName, [])) - return; - } + // Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type + if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName)) + { + if (!this.EventListeners[listener.EventType].TryAdd(listener.AddonName, [])) + return; + } - this.EventListeners[listener.EventType][listener.AddonName].Add(listener); + this.EventListeners[listener.EventType][listener.AddonName].Add(listener); + }); } /// @@ -80,13 +86,16 @@ internal unsafe class AddonLifecycle : IInternalDisposableService /// The listener to unregister. internal void UnregisterListener(AddonLifecycleEventListener listener) { - if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners)) + this.framework.RunOnFrameworkThread(() => { - if (addonListeners.TryGetValue(listener.AddonName, out var addonListener)) + if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners)) { - addonListener.Remove(listener); + if (addonListeners.TryGetValue(listener.AddonName, out var addonListener)) + { + addonListener.Remove(listener); + } } - } + }); } /// From 36c3429566478cffa01a2aa4677299d528c4b48b Mon Sep 17 00:00:00 2001 From: MidoriKami Date: Sun, 4 Jan 2026 14:41:30 -0800 Subject: [PATCH 33/99] Force to next tick instead of running immediately --- Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs b/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs index 4da8e429c..d07821149 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs @@ -31,6 +31,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService private readonly Framework framework = Service.Get(); private Hook? onInitializeAddonHook; + private bool isInvokingListeners = false; [ServiceManager.ServiceConstructor] private AddonLifecycle() @@ -61,7 +62,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService /// The listener to register. internal void RegisterListener(AddonLifecycleEventListener listener) { - this.framework.RunOnFrameworkThread(() => + this.framework.RunOnTick(() => { if (!this.EventListeners.ContainsKey(listener.EventType)) { @@ -77,7 +78,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService } this.EventListeners[listener.EventType][listener.AddonName].Add(listener); - }); + }, delayTicks: this.isInvokingListeners ? 1 : 0); } /// @@ -86,7 +87,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService /// The listener to unregister. internal void UnregisterListener(AddonLifecycleEventListener listener) { - this.framework.RunOnFrameworkThread(() => + this.framework.RunOnTick(() => { if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners)) { @@ -95,7 +96,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService addonListener.Remove(listener); } } - }); + }, delayTicks: this.isInvokingListeners ? 1 : 0); } /// @@ -106,6 +107,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService /// What to blame on errors. internal void InvokeListenersSafely(AddonEvent eventType, AddonArgs args, [CallerMemberName] string blame = "") { + this.isInvokingListeners = true; + // Early return if we don't have any listeners of this type if (!this.EventListeners.TryGetValue(eventType, out var addonListeners)) return; @@ -140,6 +143,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService } } } + + this.isInvokingListeners = false; } /// From bcc16c9b0e0d195162cbbbf38d67df9639719512 Mon Sep 17 00:00:00 2001 From: wolfcomp <4028289+wolfcomp@users.noreply.github.com> Date: Mon, 5 Jan 2026 00:00:31 +0100 Subject: [PATCH 34/99] Add CPU info to crash log (#2565) * Add CPU info to crash log Added a function to retrieve CPU vendor and brand information. * Add missing include * Remove unused std::strings --- DalamudCrashHandler/DalamudCrashHandler.cpp | 60 +++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/DalamudCrashHandler/DalamudCrashHandler.cpp b/DalamudCrashHandler/DalamudCrashHandler.cpp index 3955bd983..f28715dc1 100644 --- a/DalamudCrashHandler/DalamudCrashHandler.cpp +++ b/DalamudCrashHandler/DalamudCrashHandler.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -689,6 +690,60 @@ void restart_game_using_injector(int nRadioButton, const std::vector cpui; + int nIds_; + int nExIds_; + std::vector> data_; + std::vector> extdata_; + size_t convertedChars = 0; + + // Calling __cpuid with 0x0 as the function_id argument + // gets the number of the highest valid function ID. + __cpuid(cpui.data(), 0); + nIds_ = cpui[0]; + + for (int i = 0; i <= nIds_; ++i) + { + __cpuidex(cpui.data(), i, 0); + data_.push_back(cpui); + } + + // Capture vendor string + char vendorA[0x20]; + memset(vendorA, 0, sizeof(vendorA)); + *reinterpret_cast(vendorA) = data_[0][1]; + *reinterpret_cast(vendorA + 4) = data_[0][3]; + *reinterpret_cast(vendorA + 8) = data_[0][2]; + mbstowcs_s(&convertedChars, vendor, 0x20, vendorA, _TRUNCATE); + + // Calling __cpuid with 0x80000000 as the function_id argument + // gets the number of the highest valid extended ID. + __cpuid(cpui.data(), 0x80000000); + nExIds_ = cpui[0]; + + for (int i = 0x80000000; i <= nExIds_; ++i) + { + __cpuidex(cpui.data(), i, 0); + extdata_.push_back(cpui); + } + + // Interpret CPU brand string if reported + if (nExIds_ >= 0x80000004) + { + char brandA[0x40]; + memset(brandA, 0, sizeof(brandA)); + memcpy(brandA, extdata_[2].data(), sizeof(cpui)); + memcpy(brandA + 16, extdata_[3].data(), sizeof(cpui)); + memcpy(brandA + 32, extdata_[4].data(), sizeof(cpui)); + mbstowcs_s(&convertedChars, brand, 0x40, brandA, _TRUNCATE); + } +} + int main() { enum crash_handler_special_exit_codes { UnknownError = -99, @@ -941,6 +996,9 @@ int main() { const bool is_external_event = exinfo.ExceptionRecord.ExceptionCode == CUSTOM_EXCEPTION_EXTERNAL_EVENT; std::wostringstream log; + wchar_t vendor[0x20]; + wchar_t brand[0x40]; + get_cpu_info(vendor, brand); if (!is_external_event) { @@ -962,6 +1020,8 @@ int main() { else log << std::format(L"Dump error: {}", dumpError) << std::endl; log << std::format(L"System Time: {0:%F} {0:%T} {0:%Ez}", std::chrono::system_clock::now()) << std::endl; + log << std::format(L"CPU Vendor: {}", vendor) << std::endl; + log << std::format(L"CPU Brand: {}", brand) << std::endl; log << L"\n" << stackTrace << std::endl; if (pProgressDialog) From bd05f4c1a5a630ed2082ee8d9b0d13a18fca18d7 Mon Sep 17 00:00:00 2001 From: Infi Date: Mon, 5 Jan 2026 03:15:01 +0100 Subject: [PATCH 35/99] - Switch SeString to ReadOnlySeString - Utf8String to ReadOnlySeString avoiding Marshal - Remove unnecessary ImRaii checks - Switch default to 0 --- .../UiDebug2/Browsing/AddonTree.AtkValues.cs | 3 - .../UiDebug2/Browsing/AddonTree.FieldNames.cs | 2 +- .../Internal/UiDebug2/Browsing/AddonTree.cs | 1 - .../Internal/UiDebug2/Browsing/Events.cs | 9 +- .../UiDebug2/Browsing/NodeTree.Component.cs | 16 ++-- .../UiDebug2/Browsing/NodeTree.Counter.cs | 4 +- .../UiDebug2/Browsing/NodeTree.Editor.cs | 23 ++--- .../UiDebug2/Browsing/NodeTree.Image.cs | 2 - .../UiDebug2/Browsing/NodeTree.NineGrid.cs | 9 +- .../UiDebug2/Browsing/NodeTree.Res.cs | 2 - .../UiDebug2/Browsing/NodeTree.Text.cs | 33 +++---- .../UiDebug2/Browsing/TimelineTree.cs | 4 - .../Internal/UiDebug2/ElementSelector.cs | 86 +++++++++---------- .../Internal/UiDebug2/Popout.Addon.cs | 2 +- .../Internal/UiDebug2/Popout.Node.cs | 4 +- .../Internal/UiDebug2/Utility/Gui.cs | 13 ++- .../Internal/UiDebug2/Utility/NodeBounds.cs | 20 ++--- 17 files changed, 104 insertions(+), 129 deletions(-) diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs index b31f74264..730c2c837 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs @@ -2,9 +2,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Internal.UiDebug2.Utility; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; -using Dalamud.Memory; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -28,7 +26,6 @@ public unsafe partial class AddonTree if (tree.Success) { using var tbl = ImRaii.Table("atkUnitBase_atkValueTable"u8, 3, ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); - if (tbl.Success) { ImGui.TableSetupColumn("Index"u8); diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs index 0b1dcb66c..88a9770aa 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs @@ -41,7 +41,7 @@ public unsafe partial class AddonTree { foreach (var t in from t in ClientStructsAssembly.GetTypes() where t.IsPublic - let xivAddonAttr = (AddonAttribute?)t.GetCustomAttribute(typeof(AddonAttribute), false) + let xivAddonAttr = t.GetCustomAttribute(false) where xivAddonAttr != null where xivAddonAttr.AddonIdentifiers.Contains(this.AddonName) select t) diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs index 7cb2cc704..2e0874206 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs @@ -4,7 +4,6 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; -using Dalamud.Interface.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs index 98c7d9efe..87c793d4e 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs @@ -28,11 +28,9 @@ public static class Events } using var tree = ImRaii.TreeNode($"Events##{(nint)node:X}eventTree"); - if (tree.Success) { using var tbl = ImRaii.Table($"##{(nint)node:X}eventTable", 7, Resizable | SizingFixedFit | Borders | RowBg); - if (tbl.Success) { ImGui.TableSetupColumn("#"u8, WidthFixed); @@ -50,18 +48,25 @@ public static class Events { ImGui.TableNextColumn(); ImGui.Text($"{i++}"); + ImGui.TableNextColumn(); ImGui.Text($"{evt->State.EventType}"); + ImGui.TableNextColumn(); ImGui.Text($"{evt->Param}"); + ImGui.TableNextColumn(); ImGui.Text($"{evt->State.StateFlags}"); + ImGui.TableNextColumn(); ImGui.Text($"{evt->State.ReturnFlags}"); + ImGui.TableNextColumn(); ImGuiHelpers.ClickToCopyText($"{(nint)evt->Target:X}", default, new Vector4(0.6f, 0.6f, 0.6f, 1)); + ImGui.TableNextColumn(); ImGuiHelpers.ClickToCopyText($"{(nint)evt->Listener:X}", default, new Vector4(0.6f, 0.6f, 0.6f, 1)); + evt = evt->NextEvent; } } diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs index 922d226b6..8f34f4be6 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs @@ -3,6 +3,8 @@ using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; using FFXIVClientStructs.FFXIV.Component.GUI; +using Lumina.Text.ReadOnly; + using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; using static Dalamud.Utility.Util; using static FFXIVClientStructs.FFXIV.Component.GUI.ComponentType; @@ -89,14 +91,14 @@ internal unsafe class ComponentNodeTree : ResNodeTree { case TextInput: var textInputComponent = (AtkComponentTextInput*)this.Component; - ImGui.Text($"InputBase Text1: {Marshal.PtrToStringAnsi(new(textInputComponent->AtkComponentInputBase.EvaluatedString.StringPtr))}"); - ImGui.Text($"InputBase Text2: {Marshal.PtrToStringAnsi(new(textInputComponent->AtkComponentInputBase.RawString.StringPtr))}"); + ImGui.Text($"InputBase Text1 (Lumina): {new ReadOnlySeStringSpan(textInputComponent->AtkComponentInputBase.EvaluatedString.AsSpan()).ToMacroString()}"); + ImGui.Text($"InputBase Text2 (Lumina): {new ReadOnlySeStringSpan(textInputComponent->AtkComponentInputBase.RawString.AsSpan()).ToMacroString()}"); // TODO: Reenable when unknowns have been unprivated / named - // ImGui.Text($"Text1: {Marshal.PtrToStringAnsi(new(textInputComponent->UnkText01.StringPtr))}"); - // ImGui.Text($"Text2: {Marshal.PtrToStringAnsi(new(textInputComponent->UnkText02.StringPtr))}"); - ImGui.Text($"AvailableLines: {Marshal.PtrToStringAnsi(new(textInputComponent->AvailableLines.StringPtr))}"); - ImGui.Text($"HighlightedAutoTranslateOptionColorPrefix: {Marshal.PtrToStringAnsi(new(textInputComponent->HighlightedAutoTranslateOptionColorPrefix.StringPtr))}"); - ImGui.Text($"HighlightedAutoTranslateOptionColorSuffix: {Marshal.PtrToStringAnsi(new(textInputComponent->HighlightedAutoTranslateOptionColorSuffix.StringPtr))}"); + // ImGui.Text($"Text1: {new ReadOnlySeStringSpan(textInputComponent->UnkText01.AsSpan()).ToMacroString()}"); + // ImGui.Text($"Text2: {new ReadOnlySeStringSpan(textInputComponent->UnkText02.AsSpan()).ToMacroString()}"); + ImGui.Text($"AvailableLines: {new ReadOnlySeStringSpan(textInputComponent->AvailableLines.AsSpan()).ToMacroString()}"); + ImGui.Text($"HighlightedAutoTranslateOptionColorPrefix: {new ReadOnlySeStringSpan(textInputComponent->HighlightedAutoTranslateOptionColorPrefix.AsSpan()).ToMacroString()}"); + ImGui.Text($"HighlightedAutoTranslateOptionColorSuffix: {new ReadOnlySeStringSpan(textInputComponent->HighlightedAutoTranslateOptionColorSuffix.AsSpan()).ToMacroString()}"); break; case List: case TreeList: diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Counter.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Counter.cs index ff40db37a..2b2adbcee 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Counter.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Counter.cs @@ -1,5 +1,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI; +using Lumina.Text.ReadOnly; + using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; using static Dalamud.Utility.Util; @@ -30,7 +32,7 @@ internal unsafe partial class CounterNodeTree : ResNodeTree { if (!isEditorOpen) { - PrintFieldValuePairs(("Text", ((AtkCounterNode*)this.Node)->NodeText.ToString())); + PrintFieldValuePairs(("Text", new ReadOnlySeStringSpan(((AtkCounterNode*)this.Node)->NodeText.AsSpan()).ToMacroString())); } } } diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs index ae6f5fffa..4d1f4bb62 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs @@ -7,6 +7,8 @@ using Dalamud.Interface.Internal.UiDebug2.Utility; using Dalamud.Interface.Utility.Raii; using FFXIVClientStructs.FFXIV.Component.GUI; +using Lumina.Text.ReadOnly; + using static Dalamud.Bindings.ImGui.ImGuiColorEditFlags; using static Dalamud.Bindings.ImGui.ImGuiInputTextFlags; using static Dalamud.Bindings.ImGui.ImGuiTableColumnFlags; @@ -27,10 +29,10 @@ internal unsafe partial class ResNodeTree private protected void DrawNodeEditorTable() { using var tbl = ImRaii.Table($"###Editor{(nint)this.Node}", 2, SizingStretchProp | NoHostExtendX); - if (tbl.Success) - { - this.DrawEditorRows(); - } + if (!tbl.Success) + return; + + this.DrawEditorRows(); } /// @@ -59,7 +61,7 @@ internal unsafe partial class ResNodeTree ImGui.TableNextColumn(); ImGui.SetNextItemWidth(150); - if (ImGui.DragFloat2($"##{(nint)this.Node:X}position", ref pos, 1, default, default, "%.0f")) + if (ImGui.DragFloat2($"##{(nint)this.Node:X}position", ref pos, 1, 0, 0, "%.0f")) { this.Node->X = pos.X; this.Node->Y = pos.Y; @@ -73,7 +75,7 @@ internal unsafe partial class ResNodeTree ImGui.Text("Size:"u8); ImGui.TableNextColumn(); ImGui.SetNextItemWidth(150); - if (ImGui.DragFloat2($"##{(nint)this.Node:X}size", ref size, 1, 0, default, "%.0f")) + if (ImGui.DragFloat2($"##{(nint)this.Node:X}size", ref size, 1, 0, 0, "%.0f")) { this.Node->Width = (ushort)Math.Max(size.X, 0); this.Node->Height = (ushort)Math.Max(size.Y, 0); @@ -101,7 +103,7 @@ internal unsafe partial class ResNodeTree ImGui.Text("Origin:"u8); ImGui.TableNextColumn(); ImGui.SetNextItemWidth(150); - if (ImGui.DragFloat2($"##{(nint)this.Node:X}origin", ref origin, 1, default, default, "%.0f")) + if (ImGui.DragFloat2($"##{(nint)this.Node:X}origin", ref origin, 1, 0, 0, "%.0f")) { this.Node->OriginX = origin.X; this.Node->OriginY = origin.Y; @@ -120,7 +122,7 @@ internal unsafe partial class ResNodeTree angle -= 360; } - if (ImGui.DragFloat($"##{(nint)this.Node:X}rotation", ref angle, 0.05f, default, default, "%.2f°")) + if (ImGui.DragFloat($"##{(nint)this.Node:X}rotation", ref angle, 0.05f, 0, 0, "%.2f°")) { this.Node->Rotation = (float)(angle / (180 / Math.PI)); this.Node->DrawFlags |= 0xD; @@ -168,7 +170,6 @@ internal unsafe partial class ResNodeTree ImGui.Text("Add:"u8); ImGui.TableNextColumn(); ImGui.SetNextItemWidth(124); - if (ImGui.DragFloat3($"##{(nint)this.Node:X}addRGB", ref add, 1, -255, 255, "%.0f")) { this.Node->AddRed = (short)add.X; @@ -199,7 +200,7 @@ internal unsafe partial class CounterNodeTree { base.DrawEditorRows(); - var str = this.CntNode->NodeText.ToString(); + var str = new ReadOnlySeStringSpan(this.CntNode->NodeText.AsSpan()).ToMacroString(); ImGui.TableNextRow(); ImGui.TableNextColumn(); @@ -299,7 +300,7 @@ internal unsafe partial class TextNodeTree { base.DrawEditorRows(); - var text = this.TxtNode->NodeText.ToString(); + var text = new ReadOnlySeStringSpan(this.TxtNode->NodeText.AsSpan()).ToMacroString(); var fontIndex = FontList.IndexOf(this.TxtNode->FontType); int fontSize = this.TxtNode->FontSize; var alignment = this.TxtNode->AlignmentType; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs index 260ea4942..907261d36 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs @@ -2,7 +2,6 @@ using System.Numerics; using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -64,7 +63,6 @@ internal unsafe partial class ImageNodeTree : ResNodeTree } using var tree = ImRaii.TreeNode($"Texture##texture{(nint)this.TexData.Texture->D3D11ShaderResourceView:X}", SpanFullWidth); - if (tree.Success) { PrintFieldValuePairs( diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs index 489135ed0..1c06dfb40 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs @@ -1,6 +1,5 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface.Internal.UiDebug2.Utility; -using Dalamud.Interface.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -61,10 +60,10 @@ internal unsafe partial class NineGridNodeTree : ImageNodeTree var ngCol = RgbaVector4ToUint(col with { W = 0.75f * col.W }); - ImGui.GetWindowDrawList() - .AddRect(partBegin, partEnd, RgbaVector4ToUint(col)); - ImGui.GetWindowDrawList().AddRect(ngBegin1, ngEnd1, ngCol); - ImGui.GetWindowDrawList().AddRect(ngBegin2, ngEnd2, ngCol); + var windowDrawList = ImGui.GetWindowDrawList(); + windowDrawList.AddRect(partBegin, partEnd, RgbaVector4ToUint(col)); + windowDrawList.AddRect(ngBegin1, ngEnd1, ngCol); + windowDrawList.AddRect(ngBegin2, ngEnd2, ngCol); ImGui.SetCursorPos(cursorLocalPos + uv + new Vector2(0, -20)); ImGui.TextColored(col, $"[#{partId}]\t{part.U}, {part.V}\t{part.Width}x{part.Height}"); diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs index 418156811..4107ef53f 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs @@ -5,7 +5,6 @@ using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; using Dalamud.Interface.Internal.UiDebug2.Utility; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -138,7 +137,6 @@ internal unsafe partial class ResNodeTree : IDisposable PrintNodeList(nodeList, count, addonTree); var lineEnd = lineStart with { Y = ImGui.GetCursorScreenPos().Y - 7 }; - if (lineStart.Y < lineEnd.Y) { ImGui.GetWindowDrawList().AddLine(lineStart, lineEnd, RgbaVector4ToUint(color), 1); diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs index 1435335db..6d4fff85e 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs @@ -2,15 +2,14 @@ using System.Numerics; using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; -using Dalamud.Game.Text.SeStringHandling; -using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Interface.ImGuiSeStringRenderer; -using Dalamud.Interface.Internal.UiDebug2.Utility; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Component.GUI; +using Lumina.Text.ReadOnly; + using static Dalamud.Interface.ColorHelpers; using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; using static Dalamud.Utility.Util; @@ -64,7 +63,7 @@ internal unsafe partial class TextNodeTree : ResNodeTree } catch { - ImGui.Text(Marshal.PtrToStringAnsi(new(this.NodeText.StringPtr)) ?? string.Empty); + ImGui.Text(new ReadOnlySeStringSpan(this.NodeText.AsSpan()).ToMacroString()); } PrintFieldValuePairs( @@ -82,36 +81,24 @@ internal unsafe partial class TextNodeTree : ResNodeTree private void PrintPayloads() { using var tree = ImRaii.TreeNode($"Text Payloads##{(nint)this.Node:X}"); - if (tree.Success) { - var utf8String = this.NodeText; - var seStringBytes = new byte[utf8String.BufUsed]; - for (var i = 0L; i < utf8String.BufUsed; i++) + var idx = 0; + foreach (var payload in new ReadOnlySeString(this.NodeText.AsSpan())) { - seStringBytes[i] = utf8String.StringPtr.Value[i]; - } - - var seString = SeString.Parse(seStringBytes); - for (var i = 0; i < seString.Payloads.Count; i++) - { - var payload = seString.Payloads[i]; - ImGui.Text($"[{i}]"); + ImGui.Text($"[{idx}]"); ImGui.SameLine(); switch (payload.Type) { - case PayloadType.RawText when payload is TextPayload tp: - { - Gui.PrintFieldValuePair("Raw Text", tp.Text ?? string.Empty); + case ReadOnlySePayloadType.Text: + PrintFieldValuePair("Raw Text", payload.ToString()); break; - } - default: - { ImGui.Text(payload.ToString()); break; - } } + + idx++; } } } diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs index 21f4fb54a..3545bc2f1 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs @@ -57,7 +57,6 @@ public readonly unsafe partial struct TimelineTree if (animationCount > 0) { using var tree = ImRaii.TreeNode($"Timeline##{(nint)this.node:X}timeline", SpanFullWidth); - if (tree.Success) { PrintFieldValuePair("Timeline", $"{(nint)this.NodeTimeline:X}"); @@ -89,7 +88,6 @@ public readonly unsafe partial struct TimelineTree if (labelSetCount > 0 && this.Resource->LabelSets is not null) { using var tree = ImRaii.TreeNode($"Timeline Label Sets##{(nint)this.node:X}LabelSets", SpanFullWidth); - if (tree.Success) { this.DrawLabelSets(); @@ -324,7 +322,6 @@ public readonly unsafe partial struct TimelineTree using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1, 0.65F, 0.4F, 1), isActive)) { using var tree = ImRaii.TreeNode($"[#{a}] [Frames {animation.StartFrameIdx}-{animation.EndFrameIdx}] {(isActive ? " (Active)" : string.Empty)}###{(nint)this.node}animTree{a}"); - if (tree.Success) { PrintFieldValuePair("Animation", $"{address:X}"); @@ -334,7 +331,6 @@ public readonly unsafe partial struct TimelineTree if (columns.Count > 0) { using var tbl = ImRaii.Table($"##{(nint)this.node}animTable{a}", columns.Count, Borders | SizingFixedFit | RowBg | NoHostExtendX); - if (tbl.Success) { foreach (var c in columns) diff --git a/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs b/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs index 2ea8fd5d2..c8e2e2a55 100644 --- a/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs +++ b/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs @@ -159,65 +159,61 @@ internal unsafe class ElementSelector : IDisposable if (ch.Success) { using var gr = ImRaii.Group(); - if (gr.Success) + Gui.PrintFieldValuePair("Mouse Position", $"{mousePos.X}, {mousePos.Y}"); + ImGui.Spacing(); + ImGui.Text("RESULTS:\n"u8); + + var i = 0; + foreach (var a in addonResults) { - Gui.PrintFieldValuePair("Mouse Position", $"{mousePos.X}, {mousePos.Y}"); - ImGui.Spacing(); - ImGui.Text("RESULTS:\n"u8); + var name = a.Addon->NameString; + ImGui.Text($"[Addon] {name}"); - var i = 0; - foreach (var a in addonResults) + using var indent = ImRaii.PushIndent(15.0f); + foreach (var n in a.Nodes) { - var name = a.Addon->NameString; - ImGui.Text($"[Addon] {name}"); - ImGui.Indent(15); - foreach (var n in a.Nodes) + var nSelected = i++ == this.index; + + PrintNodeHeaderOnly(n.Node, nSelected, a.Addon); + + if (nSelected && ImGui.IsMouseClicked(ImGuiMouseButton.Left)) { - var nSelected = i++ == this.index; + this.Active = false; - PrintNodeHeaderOnly(n.Node, nSelected, a.Addon); + this.uiDebug2.SelectedAddonName = a.Addon->NameString; - if (nSelected && ImGui.IsMouseClicked(ImGuiMouseButton.Left)) + var ptrList = new List { (nint)n.Node }; + + var nextNode = n.Node->ParentNode; + while (nextNode != null) { - this.Active = false; - - this.uiDebug2.SelectedAddonName = a.Addon->NameString; - - var ptrList = new List { (nint)n.Node }; - - var nextNode = n.Node->ParentNode; - while (nextNode != null) - { - ptrList.Add((nint)nextNode); - nextNode = nextNode->ParentNode; - } - - SearchResults = [.. ptrList]; - Countdown = 100; - Scrolled = false; + ptrList.Add((nint)nextNode); + nextNode = nextNode->ParentNode; } - if (nSelected) - { - n.NodeBounds.DrawFilled(new(1, 1, 0.2f, 1)); - } + SearchResults = [.. ptrList]; + Countdown = 100; + Scrolled = false; } - ImGui.Indent(-15); + if (nSelected) + { + n.NodeBounds.DrawFilled(new(1, 1, 0.2f, 1)); + } + } + } + + if (i != 0) + { + this.index -= (int)ImGui.GetIO().MouseWheel; + while (this.index < 0) + { + this.index += i; } - if (i != 0) + while (this.index >= i) { - this.index -= (int)ImGui.GetIO().MouseWheel; - while (this.index < 0) - { - this.index += i; - } - - while (this.index >= i) - { - this.index -= i; - } + this.index -= i; } } } diff --git a/Dalamud/Interface/Internal/UiDebug2/Popout.Addon.cs b/Dalamud/Interface/Internal/UiDebug2/Popout.Addon.cs index 4684caa60..69fbc17fb 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Popout.Addon.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Popout.Addon.cs @@ -39,7 +39,7 @@ internal class AddonPopoutWindow : Window, IDisposable /// public override void Draw() { - using var ch = ImRaii.Child($"{this.WindowName}child", new(-1, -1), true); + using var ch = ImRaii.Child($"{this.WindowName}child", Vector2.Zero, true); if (ch.Success) { this.addonTree.Draw(); diff --git a/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs b/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs index da4b95256..60b51e5fb 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs @@ -38,7 +38,7 @@ internal unsafe class NodePopoutWindow : Window, IDisposable this.PositionCondition = ImGuiCond.Once; this.SizeCondition = ImGuiCond.Once; this.Size = new(700, 200); - this.SizeConstraints = new() { MinimumSize = new(100, 100) }; + this.SizeConstraints = new() { MinimumSize = new Vector2(100, 100) }; } private AddonTree AddonTree => this.resNodeTree.AddonTree; @@ -50,7 +50,7 @@ internal unsafe class NodePopoutWindow : Window, IDisposable { if (this.Node != null && this.AddonTree.ContainsNode(this.Node)) { - using var ch = ImRaii.Child($"{(nint)this.Node:X}popoutChild", new(-1, -1), true); + using var ch = ImRaii.Child($"{(nint)this.Node:X}popoutChild", Vector2.Zero, true); if (ch.Success) { ResNodeTree.GetOrCreate(this.Node, this.AddonTree).Print(null, this.firstDraw); diff --git a/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs b/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs index da5f30e68..1c293ff43 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs @@ -104,12 +104,8 @@ internal static class Gui var index = (int)Math.Floor(prog * tooltips.Length); - using var tt = ImRaii.Tooltip(); - - if (tt.Success) - { - ImGui.Text(tooltips[index]); - } + using var tooltip = ImRaii.Tooltip(); + ImGui.Text(tooltips[index]); return true; } @@ -123,13 +119,14 @@ internal static class Gui { if ((mask & 0b10) > 0) { - ImGui.Dummy(new(padding * ImGui.GetIO().FontGlobalScale)); + ImGuiHelpers.ScaledDummy(padding); } ImGui.Separator(); + if ((mask & 0b01) > 0) { - ImGui.Dummy(new(padding * ImGui.GetIO().FontGlobalScale)); + ImGuiHelpers.ScaledDummy(padding); } } } diff --git a/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs b/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs index 832c7f357..ea471476e 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs @@ -61,10 +61,11 @@ public unsafe struct NodeBounds return; } + var backgroundDrawList = ImGui.GetBackgroundDrawList(); if (this.Points.Count == 1) { - ImGui.GetBackgroundDrawList().AddCircle(this.Points[0], 10, RgbaVector4ToUint(col with { W = col.W / 2 }), 12, thickness); - ImGui.GetBackgroundDrawList().AddCircle(this.Points[0], thickness, RgbaVector4ToUint(col), 12, thickness + 1); + backgroundDrawList.AddCircle(this.Points[0], 10, RgbaVector4ToUint(col with { W = col.W / 2 }), 12, thickness); + backgroundDrawList.AddCircle(this.Points[0], thickness, RgbaVector4ToUint(col), 12, thickness + 1); } else { @@ -74,8 +75,7 @@ public unsafe struct NodeBounds path.Add(p); } - ImGui.GetBackgroundDrawList() - .AddPolyline(ref path[0], path.Length, RgbaVector4ToUint(col), ImDrawFlags.Closed, thickness); + backgroundDrawList.AddPolyline(ref path[0], path.Length, RgbaVector4ToUint(col), ImDrawFlags.Closed, thickness); path.Dispose(); } @@ -93,11 +93,11 @@ public unsafe struct NodeBounds return; } + var backgroundDrawList = ImGui.GetBackgroundDrawList(); if (this.Points.Count == 1) { - ImGui.GetBackgroundDrawList() - .AddCircleFilled(this.Points[0], 10, RgbaVector4ToUint(col with { W = col.W / 2 }), 12); - ImGui.GetBackgroundDrawList().AddCircle(this.Points[0], 10, RgbaVector4ToUint(col), 12, thickness); + backgroundDrawList.AddCircleFilled(this.Points[0], 10, RgbaVector4ToUint(col with { W = col.W / 2 }), 12); + backgroundDrawList.AddCircle(this.Points[0], 10, RgbaVector4ToUint(col), 12, thickness); } else { @@ -107,10 +107,8 @@ public unsafe struct NodeBounds path.Add(p); } - ImGui.GetBackgroundDrawList() - .AddConvexPolyFilled(ref path[0], path.Length, RgbaVector4ToUint(col with { W = col.W / 2 })); - ImGui.GetBackgroundDrawList() - .AddPolyline(ref path[0], path.Length, RgbaVector4ToUint(col), ImDrawFlags.Closed, thickness); + backgroundDrawList.AddConvexPolyFilled(ref path[0], path.Length, RgbaVector4ToUint(col with { W = col.W / 2 })); + backgroundDrawList.AddPolyline(ref path[0], path.Length, RgbaVector4ToUint(col), ImDrawFlags.Closed, thickness); path.Dispose(); } From 27414d33dd7e0ef8958c9f47341d573497490a5c Mon Sep 17 00:00:00 2001 From: bleatbot <106497096+bleatbot@users.noreply.github.com> Date: Mon, 5 Jan 2026 03:40:08 +0100 Subject: [PATCH 36/99] Update ClientStructs (#2569) Co-authored-by: github-actions[bot] --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index e1e99cf46..b6f886afc 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit e1e99cf469f87b0f3e8664ee3e3650dff86df2d6 +Subproject commit b6f886afc2b1a54d8fd76c37a260a05f214a559e From d0caf98eb3d0333ee7fb3226fefca77fecc052f0 Mon Sep 17 00:00:00 2001 From: MidoriKami Date: Sun, 4 Jan 2026 21:40:31 -0800 Subject: [PATCH 37/99] Add Agent Lifecycle --- Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs | 37 ++ .../AgentArgTypes/AgentClassJobChangeArgs.cs | 22 + .../Agent/AgentArgTypes/AgentGameEventArgs.cs | 22 + .../AgentArgTypes/AgentLevelChangeArgs.cs | 27 ++ .../AgentArgTypes/AgentReceiveEventArgs.cs | 37 ++ Dalamud/Game/Agent/AgentArgsType.cs | 32 ++ Dalamud/Game/Agent/AgentEvent.cs | 87 ++++ Dalamud/Game/Agent/AgentLifecycle.cs | 315 ++++++++++++++ .../Game/Agent/AgentLifecycleEventListener.cs | 38 ++ Dalamud/Game/Agent/AgentVirtualTable.cs | 393 ++++++++++++++++++ Dalamud/Plugin/Services/IAgentLifecycle.cs | 88 ++++ 11 files changed, 1098 insertions(+) create mode 100644 Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs create mode 100644 Dalamud/Game/Agent/AgentArgTypes/AgentClassJobChangeArgs.cs create mode 100644 Dalamud/Game/Agent/AgentArgTypes/AgentGameEventArgs.cs create mode 100644 Dalamud/Game/Agent/AgentArgTypes/AgentLevelChangeArgs.cs create mode 100644 Dalamud/Game/Agent/AgentArgTypes/AgentReceiveEventArgs.cs create mode 100644 Dalamud/Game/Agent/AgentArgsType.cs create mode 100644 Dalamud/Game/Agent/AgentEvent.cs create mode 100644 Dalamud/Game/Agent/AgentLifecycle.cs create mode 100644 Dalamud/Game/Agent/AgentLifecycleEventListener.cs create mode 100644 Dalamud/Game/Agent/AgentVirtualTable.cs create mode 100644 Dalamud/Plugin/Services/IAgentLifecycle.cs diff --git a/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs b/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs new file mode 100644 index 000000000..b4a904dde --- /dev/null +++ b/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs @@ -0,0 +1,37 @@ +namespace Dalamud.Game.Agent.AgentArgTypes; + +/// +/// Base class for AgentLifecycle AgentArgTypes. +/// +public unsafe class AgentArgs +{ + /// + /// Initializes a new instance of the class. + /// + internal AgentArgs() + { + } + + /// + /// Gets the pointer to the Agents AgentInterface*. + /// + public nint Agent { get; internal set; } + + /// + /// Gets the agent id. + /// + public uint AgentId { get; internal set; } + + /// + /// Gets the type of these args. + /// + public virtual AgentArgsType Type => AgentArgsType.Generic; + + /// + /// Gets the typed pointer to the Agents AgentInterface*. + /// + /// AgentInterface. + /// Typed pointer to contained Agents AgentInterface. + public T* GetAgentPointer() where T : unmanaged + => (T*)this.Agent; +} diff --git a/Dalamud/Game/Agent/AgentArgTypes/AgentClassJobChangeArgs.cs b/Dalamud/Game/Agent/AgentArgTypes/AgentClassJobChangeArgs.cs new file mode 100644 index 000000000..351760963 --- /dev/null +++ b/Dalamud/Game/Agent/AgentArgTypes/AgentClassJobChangeArgs.cs @@ -0,0 +1,22 @@ +namespace Dalamud.Game.Agent.AgentArgTypes; + +/// +/// Agent argument data for game events. +/// +public class AgentClassJobChangeArgs : AgentArgs +{ + /// + /// Initializes a new instance of the class. + /// + internal AgentClassJobChangeArgs() + { + } + + /// + public override AgentArgsType Type => AgentArgsType.ClassJobChange; + + /// + /// Gets or sets a value indicating what the new ClassJob is. + /// + public byte ClassJobId { get; set; } +} diff --git a/Dalamud/Game/Agent/AgentArgTypes/AgentGameEventArgs.cs b/Dalamud/Game/Agent/AgentArgTypes/AgentGameEventArgs.cs new file mode 100644 index 000000000..3da601707 --- /dev/null +++ b/Dalamud/Game/Agent/AgentArgTypes/AgentGameEventArgs.cs @@ -0,0 +1,22 @@ +namespace Dalamud.Game.Agent.AgentArgTypes; + +/// +/// Agent argument data for game events. +/// +public class AgentGameEventArgs : AgentArgs +{ + /// + /// Initializes a new instance of the class. + /// + internal AgentGameEventArgs() + { + } + + /// + public override AgentArgsType Type => AgentArgsType.GameEvent; + + /// + /// Gets or sets a value representing which gameEvent was triggered. + /// + public int GameEvent { get; set; } +} diff --git a/Dalamud/Game/Agent/AgentArgTypes/AgentLevelChangeArgs.cs b/Dalamud/Game/Agent/AgentArgTypes/AgentLevelChangeArgs.cs new file mode 100644 index 000000000..a74371ebb --- /dev/null +++ b/Dalamud/Game/Agent/AgentArgTypes/AgentLevelChangeArgs.cs @@ -0,0 +1,27 @@ +namespace Dalamud.Game.Agent.AgentArgTypes; + +/// +/// Agent argument data for game events. +/// +public class AgentLevelChangeArgs : AgentArgs +{ + /// + /// Initializes a new instance of the class. + /// + internal AgentLevelChangeArgs() + { + } + + /// + public override AgentArgsType Type => AgentArgsType.LevelChange; + + /// + /// Gets or sets a value indicating which ClassJob was switched to. + /// + public byte ClassJobId { get; set; } + + /// + /// Gets or sets a value indicating what the new level is. + /// + public ushort Level { get; set; } +} diff --git a/Dalamud/Game/Agent/AgentArgTypes/AgentReceiveEventArgs.cs b/Dalamud/Game/Agent/AgentArgTypes/AgentReceiveEventArgs.cs new file mode 100644 index 000000000..01e1f25f6 --- /dev/null +++ b/Dalamud/Game/Agent/AgentArgTypes/AgentReceiveEventArgs.cs @@ -0,0 +1,37 @@ +namespace Dalamud.Game.Agent.AgentArgTypes; + +/// +/// Agent argument data for ReceiveEvent events. +/// +public class AgentReceiveEventArgs : AgentArgs +{ + /// + /// Initializes a new instance of the class. + /// + internal AgentReceiveEventArgs() + { + } + + /// + public override AgentArgsType Type => AgentArgsType.ReceiveEvent; + + /// + /// Gets or sets the AtkValue return value for this event message. + /// + public nint ReturnValue { get; set; } + + /// + /// Gets or sets the AtkValue array for this event message. + /// + public nint AtkValues { get; set; } + + /// + /// Gets or sets the AtkValue count for this event message. + /// + public uint ValueCount { get; set; } + + /// + /// Gets or sets the event kind for this event message. + /// + public ulong EventKind { get; set; } +} diff --git a/Dalamud/Game/Agent/AgentArgsType.cs b/Dalamud/Game/Agent/AgentArgsType.cs new file mode 100644 index 000000000..0c96c0135 --- /dev/null +++ b/Dalamud/Game/Agent/AgentArgsType.cs @@ -0,0 +1,32 @@ +namespace Dalamud.Game.Agent; + +/// +/// Enumeration for available AgentLifecycle arg data. +/// +public enum AgentArgsType +{ + /// + /// Generic arg type that contains no meaningful data. + /// + Generic, + + /// + /// Contains argument data for ReceiveEvent. + /// + ReceiveEvent, + + /// + /// Contains argument data for GameEvent. + /// + GameEvent, + + /// + /// Contains argument data for LevelChange. + /// + LevelChange, + + /// + /// Contains argument data for ClassJobChange. + /// + ClassJobChange, +} diff --git a/Dalamud/Game/Agent/AgentEvent.cs b/Dalamud/Game/Agent/AgentEvent.cs new file mode 100644 index 000000000..2a3002daa --- /dev/null +++ b/Dalamud/Game/Agent/AgentEvent.cs @@ -0,0 +1,87 @@ +namespace Dalamud.Game.Agent; + +/// +/// Enumeration for available AgentLifecycle events. +/// +public enum AgentEvent +{ + /// + /// An event that is fired before the agent processes its Receive Event Function. + /// + PreReceiveEvent, + + /// + /// An event that is fired after the agent has processed its Receive Event Function. + /// + PostReceiveEvent, + + /// + /// An event that is fired before the agent processes its Filtered Receive Event Function. + /// + PreReceiveFilteredEvent, + + /// + /// An event that is fired after the agent has processed its Filtered Receive Event Function. + /// + PostReceiveFilteredEvent, + + /// + /// An event that is fired before the agent processes its Show Function. + /// + PreShow, + + /// + /// An event that is fired after the agent has processed its Show Function. + /// + PostShow, + + /// + /// An event that is fired before the agent processes its Hide Function. + /// + PreHide, + + /// + /// An event that is fired after the agent has processed its Hide Function. + /// + PostHide, + + /// + /// An event that is fired before the agent processes its Update Function. + /// + PreUpdate, + + /// + /// An event that is fired after the agent has processed its Update Function. + /// + PostUpdate, + + /// + /// An event that is fired before the agent processes its Game Event Function. + /// + PreGameEvent, + + /// + /// An event that is fired after the agent has processed its Game Event Function. + /// + PostGameEvent, + + /// + /// An event that is fired before the agent processes its Game Event Function. + /// + PreLevelChange, + + /// + /// An event that is fired after the agent has processed its Level Change Function. + /// + PostLevelChange, + + /// + /// An event that is fired before the agent processes its ClassJob Change Function. + /// + PreClassJobChange, + + /// + /// An event that is fired after the agent has processed its ClassJob Change Function. + /// + PostClassJobChange, +} diff --git a/Dalamud/Game/Agent/AgentLifecycle.cs b/Dalamud/Game/Agent/AgentLifecycle.cs new file mode 100644 index 000000000..1306a92c1 --- /dev/null +++ b/Dalamud/Game/Agent/AgentLifecycle.cs @@ -0,0 +1,315 @@ +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +using Dalamud.Game.Agent.AgentArgTypes; +using Dalamud.Hooking; +using Dalamud.IoC; +using Dalamud.IoC.Internal; +using Dalamud.Logging.Internal; +using Dalamud.Plugin.Services; + +using FFXIVClientStructs.FFXIV.Client.UI; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using FFXIVClientStructs.Interop; + +namespace Dalamud.Game.Agent; + +/// +/// This class provides events for in-game agent lifecycles. +/// +[ServiceManager.EarlyLoadedService] +internal unsafe class AgentLifecycle : IInternalDisposableService +{ + /// + /// Gets a list of all allocated agent virtual tables. + /// + public static readonly List AllocatedTables = []; + + private static readonly ModuleLog Log = new("AgentLifecycle"); + + [ServiceManager.ServiceDependency] + private readonly Framework framework = Service.Get(); + + private Hook? onInitializeAgentsHook; + private bool isInvokingListeners; + + [ServiceManager.ServiceConstructor] + private AgentLifecycle() + { + var agentModuleInstance = AgentModule.Instance(); + + // Hook is only used to determine appropriate timing for replacing Agent Virtual Tables + // If the agent module is already initialized, then we can replace the tables safely. + if (agentModuleInstance is null) + { + this.onInitializeAgentsHook = Hook.FromAddress((nint)AgentModule.MemberFunctionPointers.Ctor, this.OnAgentModuleInitialize); + this.onInitializeAgentsHook.Enable(); + } + else + { + // For safety because this might be injected async, we will make sure we are on the main thread first. + this.framework.RunOnFrameworkThread(() => this.ReplaceVirtualTables(agentModuleInstance)); + } + } + + /// + /// Gets a list of all AgentLifecycle Event Listeners. + ///
+ /// Mapping is: EventType -> ListenerList + internal Dictionary>> EventListeners { get; } = []; + + /// + void IInternalDisposableService.DisposeService() + { + this.onInitializeAgentsHook?.Dispose(); + this.onInitializeAgentsHook = null; + + AllocatedTables.ForEach(entry => entry.Dispose()); + AllocatedTables.Clear(); + } + + /// + /// Register a listener for the target event and agent. + /// + /// The listener to register. + internal void RegisterListener(AgentLifecycleEventListener listener) + { + this.framework.RunOnTick(() => + { + if (!this.EventListeners.ContainsKey(listener.EventType)) + { + if (!this.EventListeners.TryAdd(listener.EventType, [])) + return; + } + + // Note: uint.MaxValue is a valid agent id, as that will trigger on any agent for this event type + if (!this.EventListeners[listener.EventType].ContainsKey(listener.AgentId)) + { + if (!this.EventListeners[listener.EventType].TryAdd(listener.AgentId, [])) + return; + } + + this.EventListeners[listener.EventType][listener.AgentId].Add(listener); + }, + delayTicks: this.isInvokingListeners ? 1 : 0); + } + + /// + /// Unregisters the listener from events. + /// + /// The listener to unregister. + internal void UnregisterListener(AgentLifecycleEventListener listener) + { + this.framework.RunOnTick(() => + { + if (this.EventListeners.TryGetValue(listener.EventType, out var agentListeners)) + { + if (agentListeners.TryGetValue(listener.AgentId, out var agentListener)) + { + agentListener.Remove(listener); + } + } + }, + delayTicks: this.isInvokingListeners ? 1 : 0); + } + + /// + /// Invoke listeners for the specified event type. + /// + /// Event Type. + /// AgentARgs. + /// What to blame on errors. + internal void InvokeListenersSafely(AgentEvent eventType, AgentArgs args, [CallerMemberName] string blame = "") + { + this.isInvokingListeners = true; + + // Early return if we don't have any listeners of this type + if (!this.EventListeners.TryGetValue(eventType, out var agentListeners)) return; + + // Handle listeners for this event type that don't care which agent is triggering it + if (agentListeners.TryGetValue(uint.MaxValue, out var globalListeners)) + { + foreach (var listener in globalListeners) + { + try + { + listener.FunctionDelegate.Invoke(eventType, args); + } + catch (Exception e) + { + Log.Error(e, $"Exception in {blame} during {eventType} invoke, for global agent event listener."); + } + } + } + + // Handle listeners that are listening for this agent and event type specifically + if (agentListeners.TryGetValue(args.AgentId, out var agentListener)) + { + foreach (var listener in agentListener) + { + try + { + listener.FunctionDelegate.Invoke(eventType, args); + } + catch (Exception e) + { + Log.Error(e, $"Exception in {blame} during {eventType} invoke, for specific agent {(AgentId)args.AgentId}."); + } + } + } + + this.isInvokingListeners = false; + } + + /// + /// Resolves a virtual table address to the original virtual table address. + /// + /// The modified address to resolve. + /// The original address. + internal AgentInterface.AgentInterfaceVirtualTable* GetOriginalVirtualTable(AgentInterface.AgentInterfaceVirtualTable* tableAddress) + { + var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress); + if (matchedTable == null) return null; + + return matchedTable.OriginalVirtualTable; + } + + private void OnAgentModuleInitialize(AgentModule* thisPtr, UIModule* uiModule) + { + this.onInitializeAgentsHook!.Original(thisPtr, uiModule); + + try + { + this.ReplaceVirtualTables(thisPtr); + + // We don't need this hook anymore, it did its job! + this.onInitializeAgentsHook!.Dispose(); + this.onInitializeAgentsHook = null; + } + catch (Exception e) + { + Log.Error(e, "Exception in AgentLifecycle during AgentModule Ctor."); + } + } + + private void ReplaceVirtualTables(AgentModule* agentModule) + { + foreach (uint index in Enumerable.Range(0, agentModule->Agents.Length)) + { + try + { + var agentPointer = agentModule->Agents.GetPointer((int)index); + + if (agentPointer is null) + { + Log.Warning("Null Agent Found?"); + continue; + } + + // AgentVirtualTable class handles creating the virtual table, and overriding each of the tracked virtual functions + AllocatedTables.Add(new AgentVirtualTable(agentPointer->Value, index, this)); + } + catch (Exception e) + { + Log.Error(e, "Exception in AgentLifecycle during ReplaceVirtualTables."); + } + } + } +} + +/// +/// Plugin-scoped version of a AgentLifecycle service. +/// +[PluginInterface] +[ServiceManager.ScopedService] +#pragma warning disable SA1015 +[ResolveVia] +#pragma warning restore SA1015 +internal class AgentLifecyclePluginScoped : IInternalDisposableService, IAgentLifecycle +{ + [ServiceManager.ServiceDependency] + private readonly AgentLifecycle agentLifecycleService = Service.Get(); + + private readonly List eventListeners = []; + + /// + void IInternalDisposableService.DisposeService() + { + foreach (var listener in this.eventListeners) + { + this.agentLifecycleService.UnregisterListener(listener); + } + } + + /// + public void RegisterListener(AgentEvent eventType, IEnumerable agentIds, IAgentLifecycle.AgentEventDelegate handler) + { + foreach (var agentId in agentIds) + { + this.RegisterListener(eventType, agentId, handler); + } + } + + /// + public void RegisterListener(AgentEvent eventType, uint agentId, IAgentLifecycle.AgentEventDelegate handler) + { + var listener = new AgentLifecycleEventListener(eventType, agentId, handler); + this.eventListeners.Add(listener); + this.agentLifecycleService.RegisterListener(listener); + } + + /// + public void RegisterListener(AgentEvent eventType, IAgentLifecycle.AgentEventDelegate handler) + { + this.RegisterListener(eventType, uint.MaxValue, handler); + } + + /// + public void UnregisterListener(AgentEvent eventType, IEnumerable agentIds, IAgentLifecycle.AgentEventDelegate? handler = null) + { + foreach (var agentId in agentIds) + { + this.UnregisterListener(eventType, agentId, handler); + } + } + + /// + public void UnregisterListener(AgentEvent eventType, uint agentId, IAgentLifecycle.AgentEventDelegate? handler = null) + { + this.eventListeners.RemoveAll(entry => + { + if (entry.EventType != eventType) return false; + if (entry.AgentId != agentId) return false; + if (handler is not null && entry.FunctionDelegate != handler) return false; + + this.agentLifecycleService.UnregisterListener(entry); + return true; + }); + } + + /// + public void UnregisterListener(AgentEvent eventType, IAgentLifecycle.AgentEventDelegate? handler = null) + { + this.UnregisterListener(eventType, uint.MaxValue, handler); + } + + /// + public void UnregisterListener(params IAgentLifecycle.AgentEventDelegate[] handlers) + { + foreach (var handler in handlers) + { + this.eventListeners.RemoveAll(entry => + { + if (entry.FunctionDelegate != handler) return false; + + this.agentLifecycleService.UnregisterListener(entry); + return true; + }); + } + } + + /// + public unsafe nint GetOriginalVirtualTable(nint virtualTableAddress) + => (nint)this.agentLifecycleService.GetOriginalVirtualTable((AgentInterface.AgentInterfaceVirtualTable*)virtualTableAddress); +} diff --git a/Dalamud/Game/Agent/AgentLifecycleEventListener.cs b/Dalamud/Game/Agent/AgentLifecycleEventListener.cs new file mode 100644 index 000000000..3521d2c13 --- /dev/null +++ b/Dalamud/Game/Agent/AgentLifecycleEventListener.cs @@ -0,0 +1,38 @@ +using Dalamud.Plugin.Services; + +namespace Dalamud.Game.Agent; + +/// +/// This class is a helper for tracking and invoking listener delegates. +/// +public class AgentLifecycleEventListener +{ + /// + /// Initializes a new instance of the class. + /// + /// Event type to listen for. + /// Agent id to listen for. + /// Delegate to invoke. + internal AgentLifecycleEventListener(AgentEvent eventType, uint agentId, IAgentLifecycle.AgentEventDelegate functionDelegate) + { + this.EventType = eventType; + this.AgentId = agentId; + this.FunctionDelegate = functionDelegate; + } + + /// + /// Gets the agentId of the agent this listener is looking for. + /// uint.MaxValue if it wants to be called for any agent. + /// + public uint AgentId { get; init; } + + /// + /// Gets the event type this listener is looking for. + /// + public AgentEvent EventType { get; init; } + + /// + /// Gets the delegate this listener invokes. + /// + public IAgentLifecycle.AgentEventDelegate FunctionDelegate { get; init; } +} diff --git a/Dalamud/Game/Agent/AgentVirtualTable.cs b/Dalamud/Game/Agent/AgentVirtualTable.cs new file mode 100644 index 000000000..3c23616e8 --- /dev/null +++ b/Dalamud/Game/Agent/AgentVirtualTable.cs @@ -0,0 +1,393 @@ +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +using Dalamud.Game.Agent.AgentArgTypes; +using Dalamud.Logging.Internal; + +using FFXIVClientStructs.FFXIV.Client.System.Memory; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using FFXIVClientStructs.FFXIV.Component.GUI; + +namespace Dalamud.Game.Agent; + +/// +/// Represents a class that holds references to an agents original and modified virtual table entries. +/// +internal unsafe class AgentVirtualTable : IDisposable +{ + // This need to be at minimum the largest virtual table size of all agents + // Copying extra entries is not problematic, and is considered safe. + private const int VirtualTableEntryCount = 60; + + private const bool EnableLogging = true; + + private static readonly ModuleLog Log = new("AgentVT"); + + private readonly AgentLifecycle lifecycleService; + + private readonly uint agentId; + + // Each agent gets its own set of args that are used to mutate the original call when used in pre-calls + private readonly AgentReceiveEventArgs receiveEventArgs = new(); + private readonly AgentReceiveEventArgs filteredReceiveEventArgs = new(); + private readonly AgentArgs showArgs = new(); + private readonly AgentArgs hideArgs = new(); + private readonly AgentArgs updateArgs = new(); + private readonly AgentGameEventArgs gameEventArgs = new(); + private readonly AgentLevelChangeArgs levelChangeArgs = new(); + private readonly AgentClassJobChangeArgs classJobChangeArgs = new(); + + private readonly AgentInterface* agentInterface; + + // Pinned Function Delegates, as these functions get assigned to an unmanaged virtual table, + // the CLR needs to know they are in use, or it will invalidate them causing random crashing. + private readonly AgentInterface.Delegates.ReceiveEvent receiveEventFunction; + private readonly AgentInterface.Delegates.ReceiveEvent2 filteredReceiveEventFunction; + private readonly AgentInterface.Delegates.Show showFunction; + private readonly AgentInterface.Delegates.Hide hideFunction; + private readonly AgentInterface.Delegates.Update updateFunction; + private readonly AgentInterface.Delegates.OnGameEvent gameEventFunction; + private readonly AgentInterface.Delegates.OnLevelChange levelChangeFunction; + private readonly AgentInterface.Delegates.OnClassJobChange classJobChangeFunction; + + /// + /// Initializes a new instance of the class. + /// + /// AgentInterface* for the agent to replace the table of. + /// Agent ID. + /// Reference to AgentLifecycle service to callback and invoke listeners. + internal AgentVirtualTable(AgentInterface* agent, uint agentId, AgentLifecycle lifecycleService) + { + Log.Debug($"Initializing AgentVirtualTable for {(AgentId)agentId}, Address: {(nint)agent:X}"); + + this.agentInterface = agent; + this.agentId = agentId; + this.lifecycleService = lifecycleService; + + // Save original virtual table + this.OriginalVirtualTable = agent->VirtualTable; + + // Create copy of original table + // Note this will copy any derived/overriden functions that this specific agent has. + // Note: currently there are 16 virtual functions, but there's no harm in copying more for when they add new virtual functions to the game + this.ModifiedVirtualTable = (AgentInterface.AgentInterfaceVirtualTable*)IMemorySpace.GetUISpace()->Malloc(0x8 * VirtualTableEntryCount, 8); + NativeMemory.Copy(agent->VirtualTable, this.ModifiedVirtualTable, 0x8 * VirtualTableEntryCount); + + // Overwrite the agents existing virtual table with our own + agent->VirtualTable = this.ModifiedVirtualTable; + + // Pin each of our listener functions + this.receiveEventFunction = this.OnAgentReceiveEvent; + this.filteredReceiveEventFunction = this.OnAgentFilteredReceiveEvent; + this.showFunction = this.OnAgentShow; + this.hideFunction = this.OnAgentHide; + this.updateFunction = this.OnAgentUpdate; + this.gameEventFunction = this.OnAgentGameEvent; + this.levelChangeFunction = this.OnAgentLevelChange; + this.classJobChangeFunction = this.OnClassJobChange; + + // Overwrite specific virtual table entries + this.ModifiedVirtualTable->ReceiveEvent = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.receiveEventFunction); + this.ModifiedVirtualTable->ReceiveEvent2 = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.filteredReceiveEventFunction); + this.ModifiedVirtualTable->Show = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.showFunction); + this.ModifiedVirtualTable->Hide = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.hideFunction); + this.ModifiedVirtualTable->Update = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.updateFunction); + this.ModifiedVirtualTable->OnGameEvent = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.gameEventFunction); + this.ModifiedVirtualTable->OnLevelChange = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.levelChangeFunction); + this.ModifiedVirtualTable->OnClassJobChange = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.classJobChangeFunction); + } + + /// + /// Gets the original virtual table address for this agent. + /// + internal AgentInterface.AgentInterfaceVirtualTable* OriginalVirtualTable { get; private set; } + + /// + /// Gets the modified virtual address for this agent. + /// + internal AgentInterface.AgentInterfaceVirtualTable* ModifiedVirtualTable { get; private set; } + + /// + public void Dispose() + { + // Ensure restoration is done atomically. + Interlocked.Exchange(ref *(nint*)&this.agentInterface->VirtualTable, (nint)this.OriginalVirtualTable); + IMemorySpace.Free(this.ModifiedVirtualTable, 0x8 * VirtualTableEntryCount); + } + + private AtkValue* OnAgentReceiveEvent(AgentInterface* thisPtr, AtkValue* returnValue, AtkValue* values, uint valueCount, ulong eventKind) + { + AtkValue* result = null; + + try + { + this.LogEvent(EnableLogging); + + this.receiveEventArgs.Agent = (nint)thisPtr; + this.receiveEventArgs.AgentId = this.agentId; + this.receiveEventArgs.ReturnValue = (nint)returnValue; + this.receiveEventArgs.AtkValues = (nint)values; + this.receiveEventArgs.ValueCount = valueCount; + this.receiveEventArgs.EventKind = eventKind; + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PreReceiveEvent, this.receiveEventArgs); + + returnValue = (AtkValue*)this.receiveEventArgs.ReturnValue; + values = (AtkValue*)this.receiveEventArgs.AtkValues; + valueCount = this.receiveEventArgs.ValueCount; + eventKind = this.receiveEventArgs.EventKind; + + try + { + result = this.OriginalVirtualTable->ReceiveEvent(thisPtr, returnValue, values, valueCount, eventKind); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Agent ReceiveEvent. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PostReceiveEvent, this.receiveEventArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentReceiveEvent."); + } + + return result; + } + + private AtkValue* OnAgentFilteredReceiveEvent(AgentInterface* thisPtr, AtkValue* returnValue, AtkValue* values, uint valueCount, ulong eventKind) + { + AtkValue* result = null; + + try + { + this.LogEvent(EnableLogging); + + this.filteredReceiveEventArgs.Agent = (nint)thisPtr; + this.filteredReceiveEventArgs.AgentId = this.agentId; + this.filteredReceiveEventArgs.ReturnValue = (nint)returnValue; + this.filteredReceiveEventArgs.AtkValues = (nint)values; + this.filteredReceiveEventArgs.ValueCount = valueCount; + this.filteredReceiveEventArgs.EventKind = eventKind; + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PreReceiveFilteredEvent, this.filteredReceiveEventArgs); + + returnValue = (AtkValue*)this.filteredReceiveEventArgs.ReturnValue; + values = (AtkValue*)this.filteredReceiveEventArgs.AtkValues; + valueCount = this.filteredReceiveEventArgs.ValueCount; + eventKind = this.filteredReceiveEventArgs.EventKind; + + try + { + result = this.OriginalVirtualTable->ReceiveEvent2(thisPtr, returnValue, values, valueCount, eventKind); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Agent FilteredReceiveEvent. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PostReceiveFilteredEvent, this.filteredReceiveEventArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentFilteredReceiveEvent."); + } + + return result; + } + + private void OnAgentShow(AgentInterface* thisPtr) + { + try + { + this.LogEvent(EnableLogging); + + this.showArgs.Agent = (nint)thisPtr; + this.showArgs.AgentId = this.agentId; + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PreShow, this.showArgs); + + try + { + this.OriginalVirtualTable->Show(thisPtr); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Addon Show. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PostShow, this.showArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentShow."); + } + } + + private void OnAgentHide(AgentInterface* thisPtr) + { + try + { + this.LogEvent(EnableLogging); + + this.hideArgs.Agent = (nint)thisPtr; + this.hideArgs.AgentId = this.agentId; + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PreHide, this.hideArgs); + + try + { + this.OriginalVirtualTable->Hide(thisPtr); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Addon Hide. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PostHide, this.hideArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentHide."); + } + } + + private void OnAgentUpdate(AgentInterface* thisPtr, uint frameCount) + { + try + { + this.LogEvent(EnableLogging); + + this.updateArgs.Agent = (nint)thisPtr; + this.updateArgs.AgentId = this.agentId; + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PreUpdate, this.updateArgs); + + try + { + this.OriginalVirtualTable->Update(thisPtr, frameCount); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Addon Update. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PostUpdate, this.updateArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentUpdate."); + } + } + + private void OnAgentGameEvent(AgentInterface* thisPtr, AgentInterface.GameEvent gameEvent) + { + try + { + this.LogEvent(EnableLogging); + + this.gameEventArgs.Agent = (nint)thisPtr; + this.gameEventArgs.AgentId = this.agentId; + this.gameEventArgs.GameEvent = (int)gameEvent; + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PreGameEvent, this.gameEventArgs); + + gameEvent = (AgentInterface.GameEvent)this.gameEventArgs.GameEvent; + + try + { + this.OriginalVirtualTable->OnGameEvent(thisPtr, gameEvent); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Addon OnGameEvent. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PostGameEvent, this.gameEventArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentGameEvent."); + } + } + + private void OnAgentLevelChange(AgentInterface* thisPtr, byte classJobId, ushort level) + { + try + { + this.LogEvent(EnableLogging); + + this.levelChangeArgs.Agent = (nint)thisPtr; + this.levelChangeArgs.AgentId = this.agentId; + this.levelChangeArgs.ClassJobId = classJobId; + this.levelChangeArgs.Level = level; + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PreLevelChange, this.levelChangeArgs); + + classJobId = this.levelChangeArgs.ClassJobId; + level = this.levelChangeArgs.Level; + + try + { + this.OriginalVirtualTable->OnLevelChange(thisPtr, classJobId, level); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Addon OnLevelChange. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PostLevelChange, this.levelChangeArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentLevelChange."); + } + } + + private void OnClassJobChange(AgentInterface* thisPtr, byte classJobId) + { + try + { + this.LogEvent(EnableLogging); + + this.classJobChangeArgs.Agent = (nint)thisPtr; + this.classJobChangeArgs.AgentId = this.agentId; + this.classJobChangeArgs.ClassJobId = classJobId; + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PreClassJobChange, this.classJobChangeArgs); + + classJobId = this.classJobChangeArgs.ClassJobId; + + try + { + this.OriginalVirtualTable->OnClassJobChange(thisPtr, classJobId); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Addon OnClassJobChange. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AgentEvent.PostClassJobChange, this.classJobChangeArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnClassJobChange."); + } + } + + [Conditional("DEBUG")] + private void LogEvent(bool loggingEnabled, [CallerMemberName] string caller = "") + { + if (loggingEnabled) + { + // Manually disable the really spammy log events, you can comment this out if you need to debug them. + if (caller is "OnAgentUpdate" || (AgentId)this.agentId is AgentId.PadMouseMode) + return; + + Log.Debug($"[{caller}]: {(AgentId)this.agentId}"); + } + } +} diff --git a/Dalamud/Plugin/Services/IAgentLifecycle.cs b/Dalamud/Plugin/Services/IAgentLifecycle.cs new file mode 100644 index 000000000..a1ed26125 --- /dev/null +++ b/Dalamud/Plugin/Services/IAgentLifecycle.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using System.Runtime.InteropServices; + +using Dalamud.Game.Agent; +using Dalamud.Game.Agent.AgentArgTypes; + +namespace Dalamud.Plugin.Services; + +/// +/// This class provides events for in-game agent lifecycles. +/// +public interface IAgentLifecycle : IDalamudService +{ + /// + /// Delegate for receiving agent lifecycle event messages. + /// + /// The event type that triggered the message. + /// Information about what agent triggered the message. + public delegate void AgentEventDelegate(AgentEvent type, AgentArgs args); + + /// + /// Register a listener that will trigger on the specified event and any of the specified agent. + /// + /// Event type to trigger on. + /// Agent IDs that will trigger the handler to be invoked. + /// The handler to invoke. + void RegisterListener(AgentEvent eventType, IEnumerable agentIds, AgentEventDelegate handler); + + /// + /// Register a listener that will trigger on the specified event only for the specified agent. + /// + /// Event type to trigger on. + /// The agent ID that will trigger the handler to be invoked. + /// The handler to invoke. + void RegisterListener(AgentEvent eventType, uint agentId, AgentEventDelegate handler); + + /// + /// Register a listener that will trigger on the specified event for any agent. + /// + /// Event type to trigger on. + /// The handler to invoke. + void RegisterListener(AgentEvent eventType, AgentEventDelegate handler); + + /// + /// Unregister listener from specified event type and specified agent IDs. + /// + /// + /// If a specific handler is not provided, all handlers for the event type and agent IDs will be unregistered. + /// + /// Event type to deregister. + /// Agent IDs to deregister. + /// Optional specific handler to remove. + void UnregisterListener(AgentEvent eventType, IEnumerable agentIds, [Optional] AgentEventDelegate handler); + + /// + /// Unregister all listeners for the specified event type and agent ID. + /// + /// + /// If a specific handler is not provided, all handlers for the event type and agents will be unregistered. + /// + /// Event type to deregister. + /// Agent id to deregister. + /// Optional specific handler to remove. + void UnregisterListener(AgentEvent eventType, uint agentId, [Optional] AgentEventDelegate handler); + + /// + /// Unregister an event type handler.
This will only remove a handler that is added via . + ///
+ /// + /// If a specific handler is not provided, all handlers for the event type and agents will be unregistered. + /// + /// Event type to deregister. + /// Optional specific handler to remove. + void UnregisterListener(AgentEvent eventType, [Optional] AgentEventDelegate handler); + + /// + /// Unregister all events that use the specified handlers. + /// + /// Handlers to remove. + void UnregisterListener(params AgentEventDelegate[] handlers); + + /// + /// Resolves an agents virtual table address back to the original unmodified table address. + /// + /// The address of a modified agents virtual table. + /// The address of the agents original virtual table. + nint GetOriginalVirtualTable(nint virtualTableAddress); +} From e94ded628adcfcbd12f207eb6443b00482e02e6e Mon Sep 17 00:00:00 2001 From: Loskh <1020612624@qq.com> Date: Mon, 5 Jan 2026 22:42:04 +0800 Subject: [PATCH 38/99] fix: respect system dark mode setting --- .../Interface/Internal/InterfaceManager.cs | 43 ++++++++++++++++++- .../Windows/Settings/Tabs/SettingsTabLook.cs | 9 +++- Dalamud/Memory/MemoryHelper.cs | 25 +++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 96fcb7dfd..72a9eb0f2 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -32,6 +32,7 @@ using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing.Persistence; using Dalamud.IoC.Internal; using Dalamud.Logging.Internal; +using Dalamud.Memory; using Dalamud.Plugin.Services; using Dalamud.Utility; using Dalamud.Utility.Timing; @@ -500,6 +501,34 @@ internal partial class InterfaceManager : IInternalDisposableService ImGuiHelpers.ClearStacksOnContext(); } + /// + /// Applies immersive dark mode to the game window based on the current system theme setting. + /// + internal void SetImmersiveModeFromSystemTheme() + { + bool useDark = this.IsSystemInDarkMode(); + this.SetImmersiveMode(useDark); + } + + /// + /// Checks whether the system use dark mode. + /// + /// Returns true if dark mode is preferred. + internal bool IsSystemInDarkMode() + { + try + { + using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey( + @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); + var value = key?.GetValue("AppsUseLightTheme") as int?; + return value != 1; + } + catch + { + return false; + } + } + /// /// Toggle Windows 11 immersive mode on the game window. /// @@ -744,6 +773,18 @@ internal partial class InterfaceManager : IInternalDisposableService private void WndProcHookManagerOnPreWndProc(WndProcEventArgs args) { + if (args.Message == WM.WM_SETTINGCHANGE) + { + if (this.dalamudConfiguration.WindowIsImmersive) + { + if (MemoryHelper.EqualsZeroTerminatedWideString("ImmersiveColorSet", args.LParam) || + MemoryHelper.EqualsZeroTerminatedWideString("VisualStyleChanged", args.LParam)) + { + this.SetImmersiveModeFromSystemTheme(); + } + } + } + var r = this.backend?.ProcessWndProcW(args.Hwnd, args.Message, args.WParam, args.LParam); if (r is not null) args.SuppressWithValue(r.Value); @@ -858,7 +899,7 @@ internal partial class InterfaceManager : IInternalDisposableService { // Requires that game window to be there, which will be the case once game swap chain is initialized. if (Service.Get().WindowIsImmersive) - this.SetImmersiveMode(true); + this.SetImmersiveModeFromSystemTheme(); } catch (Exception ex) { diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs index 9b2c418b6..3bb16ca74 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs @@ -65,7 +65,14 @@ internal sealed class SettingsTabLook : SettingsTab { try { - Service.GetNullable()?.SetImmersiveMode(b); + if (b) + { + Service.GetNullable()?.SetImmersiveModeFromSystemTheme(); + } + else + { + Service.GetNullable()?.SetImmersiveMode(false); + } } catch (Exception ex) { diff --git a/Dalamud/Memory/MemoryHelper.cs b/Dalamud/Memory/MemoryHelper.cs index 2eae1be6d..f0f4c991f 100644 --- a/Dalamud/Memory/MemoryHelper.cs +++ b/Dalamud/Memory/MemoryHelper.cs @@ -264,6 +264,31 @@ public static unsafe class MemoryHelper } } + /// + /// Compares a UTF-16 character span with a null-terminated UTF-16 string at . + /// + /// UTF-16 character span (e.g., from a string literal). + /// Address of null-terminated UTF-16 (wide) string, as used by Windows APIs. + /// if equal; otherwise, . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool EqualsZeroTerminatedWideString( + scoped ReadOnlySpan charSpan, + nint memoryAddress) + { + if (memoryAddress == 0) + return charSpan.Length == 0; + + char* p = (char*)memoryAddress; + + foreach (char c in charSpan) + { + if (*p++ != c) + return false; + } + + return *p == '\0'; + } + /// /// Read a UTF-8 encoded string from a specified memory address. /// From 9b9a66bdd27ef73dd80c50b7d647e7760b9435d1 Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Tue, 6 Jan 2026 14:19:21 +0100 Subject: [PATCH 39/99] Update AddonEventType --- Dalamud/Game/Addon/Events/AddonEventType.cs | 65 +++++++++++++++++---- 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/Dalamud/Game/Addon/Events/AddonEventType.cs b/Dalamud/Game/Addon/Events/AddonEventType.cs index 25beb13fc..9e062a9d0 100644 --- a/Dalamud/Game/Addon/Events/AddonEventType.cs +++ b/Dalamud/Game/Addon/Events/AddonEventType.cs @@ -61,6 +61,11 @@ public enum AddonEventType : byte ///
InputBaseInputReceived = 15, + /// + /// Fired at the very beginning of AtkInputManager.HandleInput on AtkStage.ViewportEventManager. Used in LovmMiniMap. + /// + RawInputData = 16, + /// /// Focus Start. /// @@ -107,7 +112,12 @@ public enum AddonEventType : byte SliderReleased = 30, /// - /// AtkComponentList RollOver. + /// AtkComponentList Button Press. + /// + ListButtonPress = 31, + + /// + /// AtkComponentList Roll Over. /// ListItemRollOver = 33, @@ -126,11 +136,31 @@ public enum AddonEventType : byte ///
ListItemDoubleClick = 36, + /// + /// AtkComponentList Highlight. + /// + ListItemHighlight = 37, + /// /// AtkComponentList Select. /// ListItemSelect = 38, + /// + /// AtkComponentList Pad Drag Drop Begin. + /// + ListItemPadDragDropBegin = 40, + + /// + /// AtkComponentList Pad Drag Drop End. + /// + ListItemPadDragDropEnd = 41, + + /// + /// AtkComponentList Pad Drag Drop Insert. + /// + ListItemPadDragDropInsert = 42, + /// /// AtkComponentDragDrop Begin. /// Sent on MouseDown over a draggable icon (will NOT send for a locked icon). @@ -142,12 +172,22 @@ public enum AddonEventType : byte /// DragDropEnd = 51, + /// + /// AtkComponentDragDrop Insert Attempt. + /// + DragDropInsertAttempt = 52, + /// /// AtkComponentDragDrop Insert. /// Sent when dropping an icon into a hotbar/inventory slot or similar. /// DragDropInsert = 53, + /// + /// AtkComponentDragDrop Can Accept Check. + /// + DragDropCanAcceptCheck = 54, + /// /// AtkComponentDragDrop Roll Over. /// @@ -165,23 +205,18 @@ public enum AddonEventType : byte DragDropDiscard = 57, /// - /// Drag Drop Unknown. + /// AtkComponentDragDrop Click. + /// Sent on MouseUp if the cursor has not moved since DragDropBegin, OR on MouseDown over a locked icon. /// - [Obsolete("Use DragDropDiscard", true)] - DragDropUnk54 = 54, + DragDropClick = 58, /// /// AtkComponentDragDrop Cancel. /// Sent on MouseUp if the cursor has not moved since DragDropBegin, OR on MouseDown over a locked icon. /// + [Obsolete("Renamed to DragDropClick")] DragDropCancel = 58, - /// - /// Drag Drop Unknown. - /// - [Obsolete("Use DragDropCancel", true)] - DragDropUnk55 = 55, - /// /// AtkComponentIconText Roll Over. /// @@ -217,6 +252,11 @@ public enum AddonEventType : byte ///
TimerEnd = 65, + /// + /// AtkTimer Start. + /// + TimerStart = 66, + /// /// AtkSimpleTween Progress. /// @@ -247,6 +287,11 @@ public enum AddonEventType : byte ///
WindowChangeScale = 72, + /// + /// AtkTimeline Active Label Changed. + /// + TimelineActiveLabelChanged = 75, + /// /// AtkTextNode Link Mouse Click. /// From c93f04f0e47da91d5425f04f8fe44a804cffcc7a Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Tue, 6 Jan 2026 17:36:55 +0100 Subject: [PATCH 40/99] Code cleanup (#2439) * Use new Lock objects * Fix CA1513: Use ObjectDisposedException.ThrowIf * Fix CA1860: Avoid using 'Enumerable.Any()' extension method * Fix IDE0028: Use collection initializers or expressions * Fix CA2263: Prefer generic overload when type is known * Fix CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons * Fix IDE0270: Null check can be simplified * Fix IDE0280: Use 'nameof' * Fix IDE0009: Add '.this' * Fix IDE0007: Use 'var' instead of explicit type * Fix IDE0062: Make local function static * Fix CA1859: Use concrete types when possible for improved performance * Fix IDE0066: Use switch expression Only applied to where it doesn't look horrendous. * Use is over switch * Fix CA1847: Use String.Contains(char) instead of String.Contains(string) with single characters * Fix SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time. * Fix CA1866: Use 'string.EndsWith(char)' instead of 'string.EndsWith(string)' when you have a string with a single char * Fix IDE0057: Substring can be simplified * Fix IDE0059: Remove unnecessary value assignment * Fix CA1510: Use ArgumentNullException throw helper * Fix IDE0300: Use collection expression for array * Fix IDE0250: Struct can be made 'readonly' * Fix IDE0018: Inline variable declaration * Fix CA1850: Prefer static HashData method over ComputeHash * Fi CA1872: Prefer 'Convert.ToHexString' and 'Convert.ToHexStringLower' over call chains based on 'BitConverter.ToString' * Update ModuleLog instantiations * Organize usings --- .../Internal/DalamudConfiguration.cs | 20 +- .../Internal/DevPluginSettings.cs | 2 +- Dalamud/Console/ConsoleManager.cs | 13 +- Dalamud/Console/ConsoleManagerPluginScoped.cs | 4 +- Dalamud/Dalamud.cs | 2 + Dalamud/Data/DataManager.cs | 2 + Dalamud/Data/RsvResolver.cs | 4 +- Dalamud/EntryPoint.cs | 5 +- Dalamud/Game/Addon/Events/AddonEventEntry.cs | 1 - .../Game/Addon/Events/AddonEventManager.cs | 2 +- .../Addon/Events/PluginEventController.cs | 5 +- .../Game/Addon/Lifecycle/AddonLifecycle.cs | 2 +- Dalamud/Game/BaseAddressResolver.cs | 2 +- Dalamud/Game/ChatHandlers.cs | 3 +- .../ClientState/Aetherytes/AetheryteList.cs | 1 + Dalamud/Game/ClientState/ClientState.cs | 2 +- .../Game/ClientState/GamePad/GamepadState.cs | 2 + .../Game/ClientState/JobGauge/JobGauges.cs | 2 +- .../ClientState/JobGauge/Types/BRDGauge.cs | 7 +- .../ClientState/JobGauge/Types/DRKGauge.cs | 1 + .../ClientState/JobGauge/Types/PCTGauge.cs | 20 +- .../ClientState/JobGauge/Types/SMNGauge.cs | 1 + .../ClientState/JobGauge/Types/VPRGauge.cs | 12 +- .../Game/ClientState/Objects/TargetManager.cs | 28 +-- .../ClientState/Objects/Types/BattleChara.cs | 1 - .../ClientState/Objects/Types/Character.cs | 3 - Dalamud/Game/ClientState/Party/PartyList.cs | 2 +- Dalamud/Game/ClientState/Party/PartyMember.cs | 1 + .../Game/ClientState/Statuses/StatusList.cs | 2 +- Dalamud/Game/Command/CommandManager.cs | 8 +- Dalamud/Game/Config/GameConfig.cs | 4 +- Dalamud/Game/Config/GameConfigSection.cs | 4 +- Dalamud/Game/Framework.cs | 28 +-- Dalamud/Game/Gui/ChatGui.cs | 4 +- Dalamud/Game/Gui/ContextMenu/ContextMenu.cs | 5 +- Dalamud/Game/Gui/ContextMenu/MenuArgs.cs | 1 - Dalamud/Game/Gui/Dtr/DtrBar.cs | 6 +- Dalamud/Game/Gui/Dtr/DtrBarEntry.cs | 3 +- Dalamud/Game/Gui/GameGui.cs | 2 +- .../Gui/NamePlate/NamePlateUpdateHandler.cs | 4 +- .../PartyFinder/Types/JobFlagsExtensions.cs | 1 + .../Gui/PartyFinder/Types/PartyFinderSlot.cs | 18 +- Dalamud/Game/Internal/DalamudAtkTweaks.cs | 2 +- Dalamud/Game/Inventory/GameInventory.cs | 20 +- Dalamud/Game/Marketboard/MarketBoard.cs | 4 +- Dalamud/Game/NativeWrapper/AtkValuePtr.cs | 2 +- Dalamud/Game/Network/GameNetwork.cs | 3 - .../UniversalisMarketBoardUploader.cs | 4 +- .../Game/Network/Internal/NetworkHandlers.cs | 6 +- Dalamud/Game/SigScanner.cs | 2 + .../Game/Text/Evaluator/SeStringEvaluator.cs | 209 +++++------------- Dalamud/Game/Text/Noun/NounProcessor.cs | 2 +- Dalamud/Game/Text/SeStringHandling/Payload.cs | 5 +- .../SeStringHandling/Payloads/IconPayload.cs | 6 +- .../SeStringHandling/Payloads/ItemPayload.cs | 11 +- .../Payloads/MapLinkPayload.cs | 3 +- .../Payloads/NewLinePayload.cs | 2 +- .../Payloads/PartyFinderPayload.cs | 7 +- .../SeStringHandling/Payloads/QuestPayload.cs | 3 +- .../SeStringHandling/Payloads/RawPayload.cs | 2 +- .../Payloads/SeHyphenPayload.cs | 2 +- .../Payloads/StatusPayload.cs | 3 +- .../Payloads/UIForegroundPayload.cs | 7 +- .../Payloads/UIGlowPayload.cs | 7 +- .../Game/Text/SeStringHandling/SeString.cs | 2 +- Dalamud/Hooking/AsmHook.cs | 5 +- Dalamud/Hooking/Hook.cs | 7 +- .../Internal/FunctionPointerVariableHook.cs | 4 +- .../GameInteropProviderPluginScoped.cs | 5 +- Dalamud/Hooking/Internal/HookManager.cs | 5 +- Dalamud/Hooking/Internal/MinHookHook.cs | 2 +- .../Hooking/WndProcHook/WndProcHookManager.cs | 4 +- Dalamud/Interface/ColorHelpers.cs | 3 +- .../Components/ImGuiComponents.HelpMarker.cs | 1 + Dalamud/Interface/DragDrop/DragDropManager.cs | 1 + Dalamud/Interface/DragDrop/DragDropTarget.cs | 1 + .../FontAwesome/FontAwesomeExtensions.cs | 6 +- .../FontAwesome/FontAwesomeHelpers.cs | 13 +- .../DalamudAssetFontAndFamilyId.cs | 2 + .../DalamudDefaultFontAndFamilyId.cs | 2 + .../FontIdentifier/GameFontAndFamilyId.cs | 2 + .../Interface/FontIdentifier/IFontFamilyId.cs | 11 +- .../FontIdentifier/SingleFontSpec.cs | 1 + .../FontIdentifier/SystemFontFamilyId.cs | 4 +- .../Interface/FontIdentifier/SystemFontId.cs | 2 + Dalamud/Interface/GameFonts/FdtReader.cs | 6 +- .../Interface/GameFonts/GameFontLayoutPlan.cs | 45 ++-- Dalamud/Interface/GlyphRangesJapanese.cs | 6 +- .../ImGuiBackend/Dx11Win32Backend.cs | 7 - .../Renderers/Dx11Renderer.ViewportHandler.cs | 1 + .../ImGuiBackend/Renderers/Dx11Renderer.cs | 11 +- .../ImGuiFileDialog/FileDialog.Files.cs | 3 +- .../ImGuiFileDialog/FileDialog.Filters.cs | 15 +- .../ImGuiFileDialog/FileDialog.Helpers.cs | 2 +- .../ImGuiFileDialog/FileDialog.UI.cs | 20 +- .../Interface/ImGuiFileDialog/FileDialog.cs | 10 +- .../SingleFontChooserDialog.cs | 9 +- .../Internal/NotificationManager.cs | 4 +- .../ImGuiNotification/Notification.cs | 4 - .../NotificationUtilities.cs | 2 - .../Internal/SeStringRenderer.cs | 3 + .../SeStringDrawState.cs | 1 + .../Internal/Asserts/AssertHandler.cs | 2 +- Dalamud/Interface/Internal/DalamudCommands.cs | 9 +- Dalamud/Interface/Internal/DalamudIme.cs | 2 +- .../Interface/Internal/DalamudInterface.cs | 9 +- .../DalamudComponents.PluginPicker.cs | 3 +- .../ImGuiClipboardFunctionProvider.cs | 4 +- .../ImGuiInputTextStatePtrExtensions.cs | 2 +- .../Interface/Internal/InterfaceManager.cs | 13 +- .../Internal/PluginCategoryManager.cs | 8 +- Dalamud/Interface/Internal/UiDebug.cs | 9 +- .../UiDebug2/Browsing/AddonTree.AtkValues.cs | 3 +- .../UiDebug2/Browsing/AddonTree.FieldNames.cs | 4 +- .../Internal/UiDebug2/Browsing/AddonTree.cs | 1 - .../Internal/UiDebug2/Browsing/Events.cs | 1 + .../UiDebug2/Browsing/NodeTree.Component.cs | 1 + .../UiDebug2/Browsing/NodeTree.Editor.cs | 1 + .../UiDebug2/Browsing/NodeTree.Image.cs | 2 +- .../UiDebug2/Browsing/NodeTree.NineGrid.cs | 1 - .../UiDebug2/Browsing/NodeTree.Res.cs | 2 +- .../UiDebug2/Browsing/NodeTree.Text.cs | 1 + .../UiDebug2/Browsing/TimelineTree.cs | 1 + .../Internal/UiDebug2/ElementSelector.cs | 1 + .../Internal/UiDebug2/Popout.Node.cs | 1 + .../Internal/UiDebug2/UiDebug2.Sidebar.cs | 1 + .../Interface/Internal/UiDebug2/UiDebug2.cs | 7 +- .../Internal/UiDebug2/Utility/Gui.cs | 1 + .../Internal/UiDebug2/Utility/NodeBounds.cs | 1 + .../Internal/Windows/ChangelogWindow.cs | 4 +- .../Internal/Windows/ColorDemoWindow.cs | 1 - .../Internal/Windows/ComponentDemoWindow.cs | 12 +- .../Internal/Windows/ConsoleWindow.cs | 4 +- .../Internal/Windows/Data/DataWindow.cs | 5 +- .../Data/DataWindowWidgetExtensions.cs | 1 - .../Windows/Data/GameInventoryTestWidget.cs | 6 +- .../Internal/Windows/Data/WidgetUtil.cs | 1 - .../Data/Widgets/AddonInspectorWidget.cs | 2 +- .../Data/Widgets/AddonLifecycleWidget.cs | 2 +- .../Windows/Data/Widgets/AddressesWidget.cs | 4 +- .../Windows/Data/Widgets/AetherytesWidget.cs | 2 +- .../Data/Widgets/AtkArrayDataBrowserWidget.cs | 4 +- .../Windows/Data/Widgets/BuddyListWidget.cs | 2 +- .../Windows/Data/Widgets/CommandWidget.cs | 3 +- .../Windows/Data/Widgets/ConditionWidget.cs | 4 +- .../Data/Widgets/ConfigurationWidget.cs | 4 +- .../Windows/Data/Widgets/DataShareWidget.cs | 5 +- .../Windows/Data/Widgets/DtrBarWidget.cs | 4 +- .../Windows/Data/Widgets/FateTableWidget.cs | 3 +- .../Windows/Data/Widgets/FlyTextWidget.cs | 2 +- .../Data/Widgets/FontAwesomeTestWidget.cs | 2 +- .../Widgets/GamePrebakedFontsTestWidget.cs | 8 +- .../Windows/Data/Widgets/GamepadWidget.cs | 4 +- .../Windows/Data/Widgets/GaugeWidget.cs | 2 +- .../Windows/Data/Widgets/HookWidget.cs | 5 +- .../Windows/Data/Widgets/IconBrowserWidget.cs | 4 +- .../Windows/Data/Widgets/ImGuiWidget.cs | 28 +-- .../Windows/Data/Widgets/InventoryWidget.cs | 2 + .../Windows/Data/Widgets/KeyStateWidget.cs | 4 +- .../Windows/Data/Widgets/MarketBoardWidget.cs | 5 +- .../Data/Widgets/NetworkMonitorWidget.cs | 2 +- .../Data/Widgets/NounProcessorWidget.cs | 3 +- .../Windows/Data/Widgets/ObjectTableWidget.cs | 2 +- .../Windows/Data/Widgets/PartyListWidget.cs | 4 +- .../Windows/Data/Widgets/PluginIpcWidget.cs | 2 +- .../Windows/Data/Widgets/SeFontTestWidget.cs | 4 +- .../Widgets/SeStringRendererTestWidget.cs | 2 + .../Windows/Data/Widgets/ServicesWidget.cs | 18 +- .../Windows/Data/Widgets/StartInfoWidget.cs | 5 +- .../Windows/Data/Widgets/TargetWidget.cs | 2 +- .../Data/Widgets/TaskSchedulerWidget.cs | 4 +- .../Windows/Data/Widgets/TexWidget.cs | 11 +- .../Windows/Data/Widgets/ToastWidget.cs | 2 +- .../Windows/Data/Widgets/UIColorWidget.cs | 1 + .../Windows/Data/Widgets/UldWidget.cs | 1 + .../Windows/Data/Widgets/VfsWidget.cs | 3 +- .../Windows/GamepadModeNotifierWindow.cs | 1 + .../Internal/Windows/PluginImageCache.cs | 12 +- .../DalamudChangelogManager.cs | 3 +- .../PluginInstaller/PluginChangelogEntry.cs | 4 +- .../PluginInstaller/PluginInstallerWindow.cs | 13 +- .../PluginInstaller/ProfileManagerWidget.cs | 4 +- .../Internal/Windows/PluginStatWindow.cs | 6 +- .../Internal/Windows/ProfilerWindow.cs | 6 +- .../Windows/SelfTest/SelfTestWindow.cs | 7 +- .../Steps/AddonLifecycleSelfTestStep.cs | 8 +- .../SelfTest/Steps/CompletionSelfTestStep.cs | 1 - .../SelfTest/Steps/ConditionSelfTestStep.cs | 1 + .../SelfTest/Steps/ContextMenuSelfTestStep.cs | 2 + .../FrameworkTaskSchedulerSelfTestStep.cs | 2 - .../SelfTest/Steps/LuminaSelfTestStep.cs | 1 + .../SelfTest/Steps/MarketBoardSelfTestStep.cs | 1 - .../SelfTest/Steps/NamePlateSelfTestStep.cs | 2 +- .../SheetRedirectResolverSelfTestStep.cs | 1 + .../Windows/Settings/SettingsWindow.cs | 1 + .../Windows/Settings/Tabs/SettingsTabAbout.cs | 2 + .../Settings/Tabs/SettingsTabAutoUpdate.cs | 1 + .../Windows/Settings/Tabs/SettingsTabDtr.cs | 1 + .../Windows/Settings/Tabs/SettingsTabLook.cs | 1 + .../Settings/Widgets/EnumSettingsEntry{T}.cs | 2 - .../Widgets/ThirdRepoSettingsEntry.cs | 1 + .../Windows/StyleEditor/StyleEditorWindow.cs | 5 +- .../Internal/Windows/TitleScreenMenuWindow.cs | 9 +- .../FontAtlasBuildToolkitUtilities.cs | 1 - .../Internals/DelegateFontHandle.cs | 9 +- .../FontAtlasFactory.BuildToolkit.cs | 22 +- .../FontAtlasFactory.Implementation.cs | 24 +- .../Internals/FontAtlasFactory.cs | 2 + .../ManagedFontAtlas/Internals/FontHandle.cs | 3 +- .../Internals/GamePrebakedFontHandle.cs | 23 +- .../Internals/LockedImFont.cs | 3 +- .../Internals/SimplePushedFont.cs | 1 - Dalamud/Interface/Style/DalamudColors.cs | 3 +- Dalamud/Interface/Style/StyleModel.cs | 22 +- Dalamud/Interface/Style/StyleModelV1.cs | 5 +- .../ForwardingSharedImmediateTexture.cs | 3 +- .../Textures/ISharedImmediateTexture.cs | 1 - .../Textures/ImGuiViewportTextureArgs.cs | 2 - .../ManifestResourceSharedImmediateTexture.cs | 6 +- .../SharedImmediateTexture.cs | 8 +- .../Internal/TextureManager.BlameTracker.cs | 5 +- .../Internal/TextureManager.Drawer.cs | 1 + .../Internal/TextureManager.GamePath.cs | 4 +- .../Internal/TextureManager.SharedTextures.cs | 3 +- .../Textures/Internal/TextureManager.cs | 6 +- .../TextureWraps/ForwardingTextureWrap.cs | 1 - .../Internal/ViewportTextureWrap.cs | 1 + .../TitleScreenMenu/TitleScreenMenu.cs | 14 +- Dalamud/Interface/UiBuilder.cs | 3 +- Dalamud/Interface/UldWrapper.cs | 3 +- .../Utility/Internal/DevTextureSaveMenu.cs | 2 + Dalamud/Interface/Utility/Raii/Color.cs | 3 +- Dalamud/Interface/Utility/Raii/EndObjects.cs | 4 +- Dalamud/Interface/Utility/Raii/Font.cs | 1 - Dalamud/Interface/Utility/Raii/Plot.cs | 4 +- Dalamud/Interface/Utility/Raii/Style.cs | 2 +- .../Windowing/Persistence/PresetModel.cs | 2 +- Dalamud/Interface/Windowing/Window.cs | 6 +- Dalamud/Interface/Windowing/WindowSystem.cs | 3 +- Dalamud/IoC/Internal/ObjectInstance.cs | 1 - Dalamud/IoC/Internal/ServiceContainer.cs | 6 +- Dalamud/Localization.cs | 2 +- Dalamud/Logging/Internal/TaskTracker.cs | 4 +- Dalamud/Memory/MemoryHelper.cs | 4 + .../Networking/Http/HappyEyeballsCallback.cs | 4 +- Dalamud/Plugin/DalamudPluginInterface.cs | 2 +- .../Internal/AutoUpdate/AutoUpdateManager.cs | 5 +- .../Loader/AssemblyLoadContextBuilder.cs | 8 +- .../Plugin/Internal/Loader/LoaderConfig.cs | 4 +- .../Internal/Loader/ManagedLoadContext.cs | 7 +- .../Internal/Loader/PlatformInformation.cs | 10 +- .../Plugin/Internal/Loader/PluginLoader.cs | 6 +- Dalamud/Plugin/Internal/PluginErrorHandler.cs | 9 +- Dalamud/Plugin/Internal/PluginManager.cs | 24 +- Dalamud/Plugin/Internal/PluginValidator.cs | 4 +- .../PluginManagementCommandHandler.cs | 4 +- Dalamud/Plugin/Internal/Profiles/Profile.cs | 4 +- .../Internal/Profiles/ProfileManager.cs | 22 +- .../Plugin/Internal/Profiles/ProfileModel.cs | 19 +- .../Internal/Profiles/ProfileModelV1.cs | 4 +- .../Plugin/Internal/Types/LocalDevPlugin.cs | 2 +- Dalamud/Plugin/Internal/Types/LocalPlugin.cs | 2 +- .../Types/Manifest/LocalPluginManifest.cs | 2 + .../Types/Manifest/RemotePluginManifest.cs | 1 + Dalamud/Plugin/Internal/Types/PluginDef.cs | 2 +- .../Plugin/Internal/Types/PluginManifest.cs | 1 + .../Plugin/Internal/Types/PluginRepository.cs | 10 +- Dalamud/Plugin/Ipc/ICallGateProvider.cs | 1 - Dalamud/Plugin/Ipc/Internal/CallGate.cs | 2 +- .../Plugin/Ipc/Internal/CallGateChannel.cs | 3 +- Dalamud/Plugin/Ipc/Internal/DataCache.cs | 2 +- Dalamud/Plugin/Ipc/Internal/DataShare.cs | 2 +- Dalamud/SafeMemory.cs | 4 +- Dalamud/Service/ServiceManager.cs | 20 +- Dalamud/Service/Service{T}.cs | 15 +- .../Storage/Assets/IDalamudAssetManager.cs | 3 +- Dalamud/Storage/ReliableFileStorage.cs | 13 +- Dalamud/Support/BugBait.cs | 1 + Dalamud/Support/Troubleshooting.cs | 6 +- Dalamud/Utility/ArrayExtensions.cs | 6 +- Dalamud/Utility/CultureFixes.cs | 4 +- Dalamud/Utility/DateTimeSpanExtensions.cs | 2 +- Dalamud/Utility/DiagnosticUtil.cs | 4 +- Dalamud/Utility/DisposeSafety.cs | 12 +- Dalamud/Utility/DynamicPriorityQueueLoader.cs | 2 +- Dalamud/Utility/EventHandlerExtensions.cs | 1 + Dalamud/Utility/FuzzyMatcher.cs | 18 +- Dalamud/Utility/Hash.cs | 7 +- Dalamud/Utility/RollingList.cs | 2 +- Dalamud/Utility/Signatures/SignatureHelper.cs | 7 +- Dalamud/Utility/StringExtensions.cs | 4 +- .../TerraFxComInterfaceExtensions.cs | 42 ++-- Dalamud/Utility/Timing/Timings.cs | 8 +- Dalamud/Utility/Util.cs | 10 +- Dalamud/Utility/WeakConcurrentCollection.cs | 4 +- 295 files changed, 830 insertions(+), 932 deletions(-) diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs index ddcb26914..7e93d2863 100644 --- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs +++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs @@ -10,7 +10,6 @@ using System.Threading.Tasks; using Dalamud.Game.Text; using Dalamud.Interface; using Dalamud.Interface.FontIdentifier; -using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.Internal; using Dalamud.Interface.Internal.ReShadeHandling; using Dalamud.Interface.Style; @@ -20,9 +19,12 @@ using Dalamud.Plugin.Internal.AutoUpdate; using Dalamud.Plugin.Internal.Profiles; using Dalamud.Storage; using Dalamud.Utility; + using Newtonsoft.Json; + using Serilog; using Serilog.Events; + using Windows.Win32.UI.WindowsAndMessaging; namespace Dalamud.Configuration.Internal; @@ -91,7 +93,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService /// /// Gets or sets a dictionary of seen FTUE levels. /// - public Dictionary SeenFtueLevels { get; set; } = new(); + public Dictionary SeenFtueLevels { get; set; } = []; /// /// Gets or sets the last loaded Dalamud version. @@ -111,7 +113,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService /// /// Gets or sets a list of custom repos. /// - public List ThirdRepoList { get; set; } = new(); + public List ThirdRepoList { get; set; } = []; /// /// Gets or sets a value indicating whether a disclaimer regarding third-party repos has been dismissed. @@ -121,12 +123,12 @@ internal sealed class DalamudConfiguration : IInternalDisposableService /// /// Gets or sets a list of hidden plugins. /// - public List HiddenPluginInternalName { get; set; } = new(); + public List HiddenPluginInternalName { get; set; } = []; /// /// Gets or sets a list of seen plugins. /// - public List SeenPluginInternalName { get; set; } = new(); + public List SeenPluginInternalName { get; set; } = []; /// /// Gets or sets a list of additional settings for devPlugins. The key is the absolute path @@ -134,14 +136,14 @@ internal sealed class DalamudConfiguration : IInternalDisposableService /// However by specifiying this value manually, you can add arbitrary files outside the normal /// file paths. /// - public Dictionary DevPluginSettings { get; set; } = new(); + public Dictionary DevPluginSettings { get; set; } = []; /// /// Gets or sets a list of additional locations that dev plugins should be loaded from. This can /// be either a DLL or folder, but should be the absolute path, or a path relative to the currently /// injected Dalamud instance. /// - public List DevPluginLoadLocations { get; set; } = new(); + public List DevPluginLoadLocations { get; set; } = []; /// /// Gets or sets the global UI scale. @@ -223,7 +225,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService /// /// Gets or sets a list representing the command history for the Dalamud Console. /// - public List LogCommandHistory { get; set; } = new(); + public List LogCommandHistory { get; set; } = []; /// /// Gets or sets a value indicating whether the dev bar should open at startup. @@ -599,7 +601,7 @@ internal sealed class DalamudConfiguration : IInternalDisposableService { // https://source.chromium.org/chromium/chromium/src/+/main:ui/gfx/animation/animation_win.cc;l=29?q=ReducedMotion&ss=chromium var winAnimEnabled = 0; - var success = false; + bool success; unsafe { success = Windows.Win32.PInvoke.SystemParametersInfo( diff --git a/Dalamud/Configuration/Internal/DevPluginSettings.cs b/Dalamud/Configuration/Internal/DevPluginSettings.cs index 64327e658..400834cf8 100644 --- a/Dalamud/Configuration/Internal/DevPluginSettings.cs +++ b/Dalamud/Configuration/Internal/DevPluginSettings.cs @@ -31,5 +31,5 @@ internal sealed class DevPluginSettings /// /// Gets or sets a list of validation problems that have been dismissed by the user. /// - public List DismissedValidationProblems { get; set; } = new(); + public List DismissedValidationProblems { get; set; } = []; } diff --git a/Dalamud/Console/ConsoleManager.cs b/Dalamud/Console/ConsoleManager.cs index 377bac208..ba1c38b16 100644 --- a/Dalamud/Console/ConsoleManager.cs +++ b/Dalamud/Console/ConsoleManager.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; @@ -17,9 +17,9 @@ namespace Dalamud.Console; [ServiceManager.BlockingEarlyLoadedService("Console is needed by other blocking early loaded services.")] internal partial class ConsoleManager : IServiceType { - private static readonly ModuleLog Log = new("CON"); + private static readonly ModuleLog Log = ModuleLog.Create(); - private Dictionary entries = new(); + private Dictionary entries = []; /// /// Initializes a new instance of the class. @@ -99,10 +99,7 @@ internal partial class ConsoleManager : IServiceType ArgumentNullException.ThrowIfNull(name); ArgumentNullException.ThrowIfNull(alias); - var target = this.FindEntry(name); - if (target == null) - throw new EntryNotFoundException(name); - + var target = this.FindEntry(name) ?? throw new EntryNotFoundException(name); if (this.FindEntry(alias) != null) throw new InvalidOperationException($"Entry '{alias}' already exists."); @@ -346,7 +343,7 @@ internal partial class ConsoleManager : IServiceType private static class Traits { - public static void ThrowIfTIsNullableAndNull(T? argument, [CallerArgumentExpression("argument")] string? paramName = null) + public static void ThrowIfTIsNullableAndNull(T? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null) { if (argument == null && !typeof(T).IsValueType) throw new ArgumentNullException(paramName); diff --git a/Dalamud/Console/ConsoleManagerPluginScoped.cs b/Dalamud/Console/ConsoleManagerPluginScoped.cs index 41949c7d7..8e7516429 100644 --- a/Dalamud/Console/ConsoleManagerPluginScoped.cs +++ b/Dalamud/Console/ConsoleManagerPluginScoped.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -65,7 +65,7 @@ internal class ConsoleManagerPluginScoped : IConsole, IInternalDisposableService [ServiceManager.ServiceDependency] private readonly ConsoleManager console = Service.Get(); - private readonly List trackedEntries = new(); + private readonly List trackedEntries = []; /// /// Initializes a new instance of the class. diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index 2d32b8e8a..f80252ef9 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -14,7 +14,9 @@ using Dalamud.Plugin.Internal; using Dalamud.Storage; using Dalamud.Utility; using Dalamud.Utility.Timing; + using Serilog; + using Windows.Win32.Foundation; using Windows.Win32.Security; diff --git a/Dalamud/Data/DataManager.cs b/Dalamud/Data/DataManager.cs index f53195a2d..11cb3a979 100644 --- a/Dalamud/Data/DataManager.cs +++ b/Dalamud/Data/DataManager.cs @@ -8,11 +8,13 @@ using Dalamud.IoC.Internal; using Dalamud.Plugin.Services; using Dalamud.Utility; using Dalamud.Utility.Timing; + using Lumina; using Lumina.Data; using Lumina.Excel; using Newtonsoft.Json; + using Serilog; namespace Dalamud.Data; diff --git a/Dalamud/Data/RsvResolver.cs b/Dalamud/Data/RsvResolver.cs index 3f507ff1d..6fd84356c 100644 --- a/Dalamud/Data/RsvResolver.cs +++ b/Dalamud/Data/RsvResolver.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using Dalamud.Hooking; using Dalamud.Logging.Internal; using Dalamud.Memory; + using FFXIVClientStructs.FFXIV.Client.LayoutEngine; + using Lumina.Text.ReadOnly; namespace Dalamud.Data; @@ -13,7 +15,7 @@ namespace Dalamud.Data; /// internal sealed unsafe class RsvResolver : IDisposable { - private static readonly ModuleLog Log = new("RsvProvider"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly Hook addRsvStringHook; diff --git a/Dalamud/EntryPoint.cs b/Dalamud/EntryPoint.cs index d9f6ef172..7abebee3b 100644 --- a/Dalamud/EntryPoint.cs +++ b/Dalamud/EntryPoint.cs @@ -1,8 +1,6 @@ using System.ComponentModel; using System.Diagnostics; using System.IO; -using System.Net; -using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -16,10 +14,13 @@ using Dalamud.Plugin.Internal; using Dalamud.Storage; using Dalamud.Support; using Dalamud.Utility; + using Newtonsoft.Json; + using Serilog; using Serilog.Core; using Serilog.Events; + using Windows.Win32.Foundation; using Windows.Win32.UI.WindowsAndMessaging; diff --git a/Dalamud/Game/Addon/Events/AddonEventEntry.cs b/Dalamud/Game/Addon/Events/AddonEventEntry.cs index 30d0465dc..eca1903f2 100644 --- a/Dalamud/Game/Addon/Events/AddonEventEntry.cs +++ b/Dalamud/Game/Addon/Events/AddonEventEntry.cs @@ -1,5 +1,4 @@ using Dalamud.Plugin.Services; -using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; diff --git a/Dalamud/Game/Addon/Events/AddonEventManager.cs b/Dalamud/Game/Addon/Events/AddonEventManager.cs index 980404940..17b70fcc2 100644 --- a/Dalamud/Game/Addon/Events/AddonEventManager.cs +++ b/Dalamud/Game/Addon/Events/AddonEventManager.cs @@ -24,7 +24,7 @@ internal unsafe class AddonEventManager : IInternalDisposableService /// public static readonly Guid DalamudInternalKey = Guid.NewGuid(); - private static readonly ModuleLog Log = new("AddonEventManager"); + private static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceDependency] private readonly AddonLifecycle addonLifecycle = Service.Get(); diff --git a/Dalamud/Game/Addon/Events/PluginEventController.cs b/Dalamud/Game/Addon/Events/PluginEventController.cs index afaee9966..076c39cbb 100644 --- a/Dalamud/Game/Addon/Events/PluginEventController.cs +++ b/Dalamud/Game/Addon/Events/PluginEventController.cs @@ -5,7 +5,6 @@ using Dalamud.Game.Addon.Events.EventDataTypes; using Dalamud.Game.Gui; using Dalamud.Logging.Internal; using Dalamud.Plugin.Services; -using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -16,7 +15,7 @@ namespace Dalamud.Game.Addon.Events; /// internal unsafe class PluginEventController : IDisposable { - private static readonly ModuleLog Log = new("AddonEventManager"); + private static readonly ModuleLog Log = ModuleLog.Create(); /// /// Initializes a new instance of the class. @@ -28,7 +27,7 @@ internal unsafe class PluginEventController : IDisposable private AddonEventListener EventListener { get; init; } - private List Events { get; } = new(); + private List Events { get; } = []; /// /// Adds a tracked event. diff --git a/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs b/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs index 78cea1a0f..64c005b5f 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs @@ -25,7 +25,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService /// public static readonly List AllocatedTables = []; - private static readonly ModuleLog Log = new("AddonLifecycle"); + private static readonly ModuleLog Log = ModuleLog.Create(); private Hook? onInitializeAddonHook; diff --git a/Dalamud/Game/BaseAddressResolver.cs b/Dalamud/Game/BaseAddressResolver.cs index d41b1d9d8..1f20e3aeb 100644 --- a/Dalamud/Game/BaseAddressResolver.cs +++ b/Dalamud/Game/BaseAddressResolver.cs @@ -14,7 +14,7 @@ public abstract class BaseAddressResolver /// /// Gets a list of memory addresses that were found, to list in /xldata. /// - public static Dictionary> DebugScannedValues { get; } = new(); + public static Dictionary> DebugScannedValues { get; } = []; /// /// Gets or sets a value indicating whether the resolver has successfully run or . diff --git a/Dalamud/Game/ChatHandlers.cs b/Dalamud/Game/ChatHandlers.cs index 279bf46e5..2d7d3c83a 100644 --- a/Dalamud/Game/ChatHandlers.cs +++ b/Dalamud/Game/ChatHandlers.cs @@ -1,5 +1,4 @@ using System.Linq; -using System.Reflection; using System.Text.RegularExpressions; using CheapLoc; @@ -23,7 +22,7 @@ namespace Dalamud.Game; [ServiceManager.EarlyLoadedService] internal partial class ChatHandlers : IServiceType { - private static readonly ModuleLog Log = new("ChatHandlers"); + private static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceDependency] private readonly DalamudConfiguration configuration = Service.Get(); diff --git a/Dalamud/Game/ClientState/Aetherytes/AetheryteList.cs b/Dalamud/Game/ClientState/Aetherytes/AetheryteList.cs index 12a629958..2df64b73b 100644 --- a/Dalamud/Game/ClientState/Aetherytes/AetheryteList.cs +++ b/Dalamud/Game/ClientState/Aetherytes/AetheryteList.cs @@ -8,6 +8,7 @@ using Dalamud.Plugin.Services; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.Game.UI; + using Serilog; namespace Dalamud.Game.ClientState.Aetherytes; diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs index f7c0b75ed..304dde82c 100644 --- a/Dalamud/Game/ClientState/ClientState.cs +++ b/Dalamud/Game/ClientState/ClientState.cs @@ -33,7 +33,7 @@ namespace Dalamud.Game.ClientState; [ServiceManager.EarlyLoadedService] internal sealed class ClientState : IInternalDisposableService, IClientState { - private static readonly ModuleLog Log = new("ClientState"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly GameLifecycle lifecycle; private readonly ClientStateAddressResolver address; diff --git a/Dalamud/Game/ClientState/GamePad/GamepadState.cs b/Dalamud/Game/ClientState/GamePad/GamepadState.cs index ab4f8a03f..3a8642cfa 100644 --- a/Dalamud/Game/ClientState/GamePad/GamepadState.cs +++ b/Dalamud/Game/ClientState/GamePad/GamepadState.cs @@ -5,7 +5,9 @@ using Dalamud.Hooking; using Dalamud.IoC; using Dalamud.IoC.Internal; using Dalamud.Plugin.Services; + using FFXIVClientStructs.FFXIV.Client.System.Input; + using Serilog; namespace Dalamud.Game.ClientState.GamePad; diff --git a/Dalamud/Game/ClientState/JobGauge/JobGauges.cs b/Dalamud/Game/ClientState/JobGauge/JobGauges.cs index 67429956b..5d6ba4554 100644 --- a/Dalamud/Game/ClientState/JobGauge/JobGauges.cs +++ b/Dalamud/Game/ClientState/JobGauge/JobGauges.cs @@ -37,7 +37,7 @@ internal class JobGauges : IServiceType, IJobGauges // Since the gauge itself reads from live memory, there isn't much downside to doing this. if (!this.cache.TryGetValue(typeof(T), out var gauge)) { - gauge = this.cache[typeof(T)] = (T)Activator.CreateInstance(typeof(T), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { this.Address }, null); + gauge = this.cache[typeof(T)] = (T)Activator.CreateInstance(typeof(T), BindingFlags.NonPublic | BindingFlags.Instance, null, [this.Address], null); } return (T)gauge; diff --git a/Dalamud/Game/ClientState/JobGauge/Types/BRDGauge.cs b/Dalamud/Game/ClientState/JobGauge/Types/BRDGauge.cs index 8880c3555..de73d540e 100644 --- a/Dalamud/Game/ClientState/JobGauge/Types/BRDGauge.cs +++ b/Dalamud/Game/ClientState/JobGauge/Types/BRDGauge.cs @@ -1,4 +1,5 @@ using Dalamud.Game.ClientState.JobGauge.Enums; + using FFXIVClientStructs.FFXIV.Client.Game.Gauge; namespace Dalamud.Game.ClientState.JobGauge.Types; @@ -82,12 +83,12 @@ public unsafe class BRDGauge : JobGaugeBaseSongFlags.HasFlag(SongFlags.MagesBalladCoda) ? Song.Mage : Song.None, this.Struct->SongFlags.HasFlag(SongFlags.ArmysPaeonCoda) ? Song.Army : Song.None, this.Struct->SongFlags.HasFlag(SongFlags.WanderersMinuetCoda) ? Song.Wanderer : Song.None, - }; + ]; } } } diff --git a/Dalamud/Game/ClientState/JobGauge/Types/DRKGauge.cs b/Dalamud/Game/ClientState/JobGauge/Types/DRKGauge.cs index c56d03db0..06d923cc4 100644 --- a/Dalamud/Game/ClientState/JobGauge/Types/DRKGauge.cs +++ b/Dalamud/Game/ClientState/JobGauge/Types/DRKGauge.cs @@ -1,4 +1,5 @@ using Dalamud.Game.ClientState.JobGauge.Enums; + using FFXIVClientStructs.FFXIV.Client.Game.Gauge; namespace Dalamud.Game.ClientState.JobGauge.Types; diff --git a/Dalamud/Game/ClientState/JobGauge/Types/PCTGauge.cs b/Dalamud/Game/ClientState/JobGauge/Types/PCTGauge.cs index d31a22702..9745bff7c 100644 --- a/Dalamud/Game/ClientState/JobGauge/Types/PCTGauge.cs +++ b/Dalamud/Game/ClientState/JobGauge/Types/PCTGauge.cs @@ -1,4 +1,4 @@ -using FFXIVClientStructs.FFXIV.Client.Game.Gauge; +using FFXIVClientStructs.FFXIV.Client.Game.Gauge; using CanvasFlags = Dalamud.Game.ClientState.JobGauge.Enums.CanvasFlags; using CreatureFlags = Dalamud.Game.ClientState.JobGauge.Enums.CreatureFlags; @@ -22,45 +22,45 @@ public unsafe class PCTGauge : JobGaugeBase /// /// Gets the use of subjective pallete. /// - public byte PalleteGauge => Struct->PalleteGauge; + public byte PalleteGauge => this.Struct->PalleteGauge; /// /// Gets the amount of paint the player has. /// - public byte Paint => Struct->Paint; + public byte Paint => this.Struct->Paint; /// /// Gets a value indicating whether a creature motif is drawn. /// - public bool CreatureMotifDrawn => Struct->CreatureMotifDrawn; + public bool CreatureMotifDrawn => this.Struct->CreatureMotifDrawn; /// /// Gets a value indicating whether a weapon motif is drawn. /// - public bool WeaponMotifDrawn => Struct->WeaponMotifDrawn; + public bool WeaponMotifDrawn => this.Struct->WeaponMotifDrawn; /// /// Gets a value indicating whether a landscape motif is drawn. /// - public bool LandscapeMotifDrawn => Struct->LandscapeMotifDrawn; + public bool LandscapeMotifDrawn => this.Struct->LandscapeMotifDrawn; /// /// Gets a value indicating whether a moogle portrait is ready. /// - public bool MooglePortraitReady => Struct->MooglePortraitReady; + public bool MooglePortraitReady => this.Struct->MooglePortraitReady; /// /// Gets a value indicating whether a madeen portrait is ready. /// - public bool MadeenPortraitReady => Struct->MadeenPortraitReady; + public bool MadeenPortraitReady => this.Struct->MadeenPortraitReady; /// /// Gets which creature flags are present. /// - public CreatureFlags CreatureFlags => (CreatureFlags)Struct->CreatureFlags; + public CreatureFlags CreatureFlags => (CreatureFlags)this.Struct->CreatureFlags; /// /// Gets which canvas flags are present. /// - public CanvasFlags CanvasFlags => (CanvasFlags)Struct->CanvasFlags; + public CanvasFlags CanvasFlags => (CanvasFlags)this.Struct->CanvasFlags; } diff --git a/Dalamud/Game/ClientState/JobGauge/Types/SMNGauge.cs b/Dalamud/Game/ClientState/JobGauge/Types/SMNGauge.cs index 899ea78eb..5f2d6e932 100644 --- a/Dalamud/Game/ClientState/JobGauge/Types/SMNGauge.cs +++ b/Dalamud/Game/ClientState/JobGauge/Types/SMNGauge.cs @@ -1,4 +1,5 @@ using Dalamud.Game.ClientState.JobGauge.Enums; + using FFXIVClientStructs.FFXIV.Client.Game.Gauge; namespace Dalamud.Game.ClientState.JobGauge.Types; diff --git a/Dalamud/Game/ClientState/JobGauge/Types/VPRGauge.cs b/Dalamud/Game/ClientState/JobGauge/Types/VPRGauge.cs index 3c822c7d7..625ecde24 100644 --- a/Dalamud/Game/ClientState/JobGauge/Types/VPRGauge.cs +++ b/Dalamud/Game/ClientState/JobGauge/Types/VPRGauge.cs @@ -1,7 +1,5 @@ using FFXIVClientStructs.FFXIV.Client.Game.Gauge; -using Reloaded.Memory; - using DreadCombo = Dalamud.Game.ClientState.JobGauge.Enums.DreadCombo; using SerpentCombo = Dalamud.Game.ClientState.JobGauge.Enums.SerpentCombo; @@ -24,25 +22,25 @@ public unsafe class VPRGauge : JobGaugeBase /// /// Gets how many uses of uncoiled fury the player has. /// - public byte RattlingCoilStacks => Struct->RattlingCoilStacks; + public byte RattlingCoilStacks => this.Struct->RattlingCoilStacks; /// /// Gets Serpent Offering stacks and gauge. /// - public byte SerpentOffering => Struct->SerpentOffering; + public byte SerpentOffering => this.Struct->SerpentOffering; /// /// Gets value indicating the use of 1st, 2nd, 3rd, 4th generation and Ouroboros. /// - public byte AnguineTribute => Struct->AnguineTribute; + public byte AnguineTribute => this.Struct->AnguineTribute; /// /// Gets the last Weaponskill used in DreadWinder/Pit of Dread combo. /// - public DreadCombo DreadCombo => (DreadCombo)Struct->DreadCombo; + public DreadCombo DreadCombo => (DreadCombo)this.Struct->DreadCombo; /// /// Gets current ability for Serpent's Tail. /// - public SerpentCombo SerpentCombo => (SerpentCombo)Struct->SerpentCombo; + public SerpentCombo SerpentCombo => (SerpentCombo)this.Struct->SerpentCombo; } diff --git a/Dalamud/Game/ClientState/Objects/TargetManager.cs b/Dalamud/Game/ClientState/Objects/TargetManager.cs index a6432e242..5f317d077 100644 --- a/Dalamud/Game/ClientState/Objects/TargetManager.cs +++ b/Dalamud/Game/ClientState/Objects/TargetManager.cs @@ -30,50 +30,50 @@ internal sealed unsafe class TargetManager : IServiceType, ITargetManager /// public IGameObject? Target { - get => this.objectTable.CreateObjectReference((IntPtr)Struct->GetHardTarget()); - set => Struct->SetHardTarget((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address); + get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->GetHardTarget()); + set => this.Struct->SetHardTarget((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address); } /// public IGameObject? MouseOverTarget { - get => this.objectTable.CreateObjectReference((IntPtr)Struct->MouseOverTarget); - set => Struct->MouseOverTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; + get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->MouseOverTarget); + set => this.Struct->MouseOverTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; } /// public IGameObject? FocusTarget { - get => this.objectTable.CreateObjectReference((IntPtr)Struct->FocusTarget); - set => Struct->FocusTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; + get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->FocusTarget); + set => this.Struct->FocusTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; } /// public IGameObject? PreviousTarget { - get => this.objectTable.CreateObjectReference((IntPtr)Struct->PreviousTarget); - set => Struct->PreviousTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; + get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->PreviousTarget); + set => this.Struct->PreviousTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; } /// public IGameObject? SoftTarget { - get => this.objectTable.CreateObjectReference((IntPtr)Struct->GetSoftTarget()); - set => Struct->SetSoftTarget((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address); + get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->GetSoftTarget()); + set => this.Struct->SetSoftTarget((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address); } /// public IGameObject? GPoseTarget { - get => this.objectTable.CreateObjectReference((IntPtr)Struct->GPoseTarget); - set => Struct->GPoseTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; + get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->GPoseTarget); + set => this.Struct->GPoseTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; } /// public IGameObject? MouseOverNameplateTarget { - get => this.objectTable.CreateObjectReference((IntPtr)Struct->MouseOverNameplateTarget); - set => Struct->MouseOverNameplateTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; + get => this.objectTable.CreateObjectReference((IntPtr)this.Struct->MouseOverNameplateTarget); + set => this.Struct->MouseOverNameplateTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)value?.Address; } private TargetSystem* Struct => TargetSystem.Instance(); diff --git a/Dalamud/Game/ClientState/Objects/Types/BattleChara.cs b/Dalamud/Game/ClientState/Objects/Types/BattleChara.cs index 238c81a72..37f1f5504 100644 --- a/Dalamud/Game/ClientState/Objects/Types/BattleChara.cs +++ b/Dalamud/Game/ClientState/Objects/Types/BattleChara.cs @@ -1,5 +1,4 @@ using Dalamud.Game.ClientState.Statuses; -using Dalamud.Utility; namespace Dalamud.Game.ClientState.Objects.Types; diff --git a/Dalamud/Game/ClientState/Objects/Types/Character.cs b/Dalamud/Game/ClientState/Objects/Types/Character.cs index a91ecc230..2002a16b8 100644 --- a/Dalamud/Game/ClientState/Objects/Types/Character.cs +++ b/Dalamud/Game/ClientState/Objects/Types/Character.cs @@ -1,9 +1,6 @@ -using System.Runtime.CompilerServices; - using Dalamud.Data; using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.Text.SeStringHandling; -using Dalamud.Memory; using Lumina.Excel; using Lumina.Excel.Sheets; diff --git a/Dalamud/Game/ClientState/Party/PartyList.cs b/Dalamud/Game/ClientState/Party/PartyList.cs index 90959f926..0326350d2 100644 --- a/Dalamud/Game/ClientState/Party/PartyList.cs +++ b/Dalamud/Game/ClientState/Party/PartyList.cs @@ -47,7 +47,7 @@ internal sealed unsafe partial class PartyList : IServiceType, IPartyList public unsafe nint GroupManagerAddress => (nint)CSGroupManager.Instance(); /// - public nint GroupListAddress => (nint)Unsafe.AsPointer(ref GroupManagerStruct->MainGroup.PartyMembers[0]); + public nint GroupListAddress => (nint)Unsafe.AsPointer(ref this.GroupManagerStruct->MainGroup.PartyMembers[0]); /// public nint AllianceListAddress => (nint)Unsafe.AsPointer(ref this.GroupManagerStruct->MainGroup.AllianceMembers[0]); diff --git a/Dalamud/Game/ClientState/Party/PartyMember.cs b/Dalamud/Game/ClientState/Party/PartyMember.cs index 84e3f21c8..843824318 100644 --- a/Dalamud/Game/ClientState/Party/PartyMember.cs +++ b/Dalamud/Game/ClientState/Party/PartyMember.cs @@ -6,6 +6,7 @@ using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Statuses; using Dalamud.Game.Text.SeStringHandling; + using Dalamud.Utility; using Lumina.Excel; diff --git a/Dalamud/Game/ClientState/Statuses/StatusList.cs b/Dalamud/Game/ClientState/Statuses/StatusList.cs index 43650a48c..2e8024ab8 100644 --- a/Dalamud/Game/ClientState/Statuses/StatusList.cs +++ b/Dalamud/Game/ClientState/Statuses/StatusList.cs @@ -38,7 +38,7 @@ public sealed unsafe partial class StatusList /// /// Gets the amount of status effect slots the actor has. /// - public int Length => Struct->NumValidStatuses; + public int Length => this.Struct->NumValidStatuses; private static int StatusSize { get; } = Marshal.SizeOf(); diff --git a/Dalamud/Game/Command/CommandManager.cs b/Dalamud/Game/Command/CommandManager.cs index 01442c409..e9abb7336 100644 --- a/Dalamud/Game/Command/CommandManager.cs +++ b/Dalamud/Game/Command/CommandManager.cs @@ -24,7 +24,7 @@ namespace Dalamud.Game.Command; [ServiceManager.EarlyLoadedService] internal sealed unsafe class CommandManager : IInternalDisposableService, ICommandManager { - private static readonly ModuleLog Log = new("Command"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly ConcurrentDictionary commandMap = new(); private readonly ConcurrentDictionary<(string, IReadOnlyCommandInfo), string> commandAssemblyNameMap = new(); @@ -71,7 +71,7 @@ internal sealed unsafe class CommandManager : IInternalDisposableService, IComma if (separatorPosition + 1 >= content.Length) { // Remove the trailing space - command = content.Substring(0, separatorPosition); + command = content[..separatorPosition]; } else { @@ -262,12 +262,12 @@ internal sealed unsafe class CommandManager : IInternalDisposableService, IComma #pragma warning restore SA1015 internal class CommandManagerPluginScoped : IInternalDisposableService, ICommandManager { - private static readonly ModuleLog Log = new("Command"); + private static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceDependency] private readonly CommandManager commandManagerService = Service.Get(); - private readonly List pluginRegisteredCommands = new(); + private readonly List pluginRegisteredCommands = []; private readonly LocalPlugin pluginInfo; /// diff --git a/Dalamud/Game/Config/GameConfig.cs b/Dalamud/Game/Config/GameConfig.cs index 9579d84bc..a55056351 100644 --- a/Dalamud/Game/Config/GameConfig.cs +++ b/Dalamud/Game/Config/GameConfig.cs @@ -1,11 +1,13 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using Dalamud.Hooking; using Dalamud.IoC; using Dalamud.IoC.Internal; using Dalamud.Plugin.Services; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Common.Configuration; + using Serilog; namespace Dalamud.Game.Config; diff --git a/Dalamud/Game/Config/GameConfigSection.cs b/Dalamud/Game/Config/GameConfigSection.cs index 8ebab8a60..eb2f1107e 100644 --- a/Dalamud/Game/Config/GameConfigSection.cs +++ b/Dalamud/Game/Config/GameConfigSection.cs @@ -1,10 +1,12 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Diagnostics; using System.Text; using Dalamud.Memory; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Common.Configuration; + using Serilog; namespace Dalamud.Game.Config; diff --git a/Dalamud/Game/Framework.cs b/Dalamud/Game/Framework.cs index 808bbce50..035745684 100644 --- a/Dalamud/Game/Framework.cs +++ b/Dalamud/Game/Framework.cs @@ -26,7 +26,7 @@ namespace Dalamud.Game; [ServiceManager.EarlyLoadedService] internal sealed class Framework : IInternalDisposableService, IFramework { - private static readonly ModuleLog Log = new("Framework"); + private static readonly ModuleLog Log = ModuleLog.Create(); private static readonly Stopwatch StatsStopwatch = new(); @@ -86,7 +86,7 @@ internal sealed class Framework : IInternalDisposableService, IFramework /// /// Gets the stats history mapping. /// - public static Dictionary> StatsHistory { get; } = new(); + public static Dictionary> StatsHistory { get; } = []; /// public DateTime LastUpdate { get; private set; } = DateTime.MinValue; @@ -106,7 +106,7 @@ internal sealed class Framework : IInternalDisposableService, IFramework /// /// Gets the list of update sub-delegates that didn't get updated this frame. /// - internal List NonUpdatedSubDelegates { get; private set; } = new(); + internal List NonUpdatedSubDelegates { get; private set; } = []; /// /// Gets or sets a value indicating whether to dispatch update events. @@ -212,11 +212,10 @@ internal sealed class Framework : IInternalDisposableService, IFramework if (cancellationToken == default) cancellationToken = this.FrameworkThreadTaskFactory.CancellationToken; return this.FrameworkThreadTaskFactory.ContinueWhenAll( - new[] - { + [ Task.Delay(delay, cancellationToken), this.DelayTicks(delayTicks, cancellationToken), - }, + ], _ => func(), cancellationToken, TaskContinuationOptions.HideScheduler, @@ -239,11 +238,10 @@ internal sealed class Framework : IInternalDisposableService, IFramework if (cancellationToken == default) cancellationToken = this.FrameworkThreadTaskFactory.CancellationToken; return this.FrameworkThreadTaskFactory.ContinueWhenAll( - new[] - { + [ Task.Delay(delay, cancellationToken), this.DelayTicks(delayTicks, cancellationToken), - }, + ], _ => action(), cancellationToken, TaskContinuationOptions.HideScheduler, @@ -266,11 +264,10 @@ internal sealed class Framework : IInternalDisposableService, IFramework if (cancellationToken == default) cancellationToken = this.FrameworkThreadTaskFactory.CancellationToken; return this.FrameworkThreadTaskFactory.ContinueWhenAll( - new[] - { + [ Task.Delay(delay, cancellationToken), this.DelayTicks(delayTicks, cancellationToken), - }, + ], _ => func(), cancellationToken, TaskContinuationOptions.HideScheduler, @@ -293,11 +290,10 @@ internal sealed class Framework : IInternalDisposableService, IFramework if (cancellationToken == default) cancellationToken = this.FrameworkThreadTaskFactory.CancellationToken; return this.FrameworkThreadTaskFactory.ContinueWhenAll( - new[] - { + [ Task.Delay(delay, cancellationToken), this.DelayTicks(delayTicks, cancellationToken), - }, + ], _ => func(), cancellationToken, TaskContinuationOptions.HideScheduler, @@ -333,7 +329,7 @@ internal sealed class Framework : IInternalDisposableService, IFramework internal static void AddToStats(string key, double ms) { if (!StatsHistory.ContainsKey(key)) - StatsHistory.Add(key, new List()); + StatsHistory.Add(key, []); StatsHistory[key].Add(ms); diff --git a/Dalamud/Game/Gui/ChatGui.cs b/Dalamud/Game/Gui/ChatGui.cs index 30e2b676c..e9a0a1aae 100644 --- a/Dalamud/Game/Gui/ChatGui.cs +++ b/Dalamud/Game/Gui/ChatGui.cs @@ -37,10 +37,10 @@ namespace Dalamud.Game.Gui; [ServiceManager.EarlyLoadedService] internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui { - private static readonly ModuleLog Log = new("ChatGui"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly Queue chatQueue = new(); - private readonly Dictionary<(string PluginName, uint CommandId), Action> dalamudLinkHandlers = new(); + private readonly Dictionary<(string PluginName, uint CommandId), Action> dalamudLinkHandlers = []; private readonly Hook printMessageHook; private readonly Hook inventoryItemCopyHook; diff --git a/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs b/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs index aada374ec..0b306f093 100644 --- a/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs +++ b/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; @@ -28,7 +29,7 @@ namespace Dalamud.Game.Gui.ContextMenu; [ServiceManager.EarlyLoadedService] internal sealed unsafe class ContextMenu : IInternalDisposableService, IContextMenu { - private static readonly ModuleLog Log = new("ContextMenu"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly Hook atkModuleVf22OpenAddonByAgentHook; private readonly Hook addonContextMenuOnMenuSelectedHook; @@ -53,7 +54,7 @@ internal sealed unsafe class ContextMenu : IInternalDisposableService, IContextM private Dictionary> MenuItems { get; } = []; - private object MenuItemsLock { get; } = new(); + private Lock MenuItemsLock { get; } = new(); private AgentInterface* SelectedAgent { get; set; } diff --git a/Dalamud/Game/Gui/ContextMenu/MenuArgs.cs b/Dalamud/Game/Gui/ContextMenu/MenuArgs.cs index 39fd1c52c..900935ed5 100644 --- a/Dalamud/Game/Gui/ContextMenu/MenuArgs.cs +++ b/Dalamud/Game/Gui/ContextMenu/MenuArgs.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; -using Dalamud.Memory; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.UI.Agent; diff --git a/Dalamud/Game/Gui/Dtr/DtrBar.cs b/Dalamud/Game/Gui/Dtr/DtrBar.cs index 2235c5ade..5663d0748 100644 --- a/Dalamud/Game/Gui/Dtr/DtrBar.cs +++ b/Dalamud/Game/Gui/Dtr/DtrBar.cs @@ -30,7 +30,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar { private const uint BaseNodeId = 1000; - private static readonly ModuleLog Log = new("DtrBar"); + private static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceDependency] private readonly Framework framework = Service.Get(); @@ -54,7 +54,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar private readonly ReaderWriterLockSlim entriesLock = new(); private readonly List entries = []; - private readonly Dictionary> eventHandles = new(); + private readonly Dictionary> eventHandles = []; private ImmutableList? entriesReadOnlyCopy; @@ -516,7 +516,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar var node = data.TextNode = this.MakeNode(++this.runningNodeIds); - this.eventHandles.TryAdd(node->NodeId, new List()); + this.eventHandles.TryAdd(node->NodeId, []); this.eventHandles[node->NodeId].AddRange(new List { this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, (nint)dtr, (nint)node, AddonEventType.MouseOver, this.DtrEventHandler), diff --git a/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs b/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs index 138484580..e0bd8fd49 100644 --- a/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs +++ b/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs @@ -1,7 +1,6 @@ -using System.Numerics; +using System.Numerics; using Dalamud.Configuration.Internal; -using Dalamud.Game.Addon.Events.EventDataTypes; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.Internal.Types; using Dalamud.Utility; diff --git a/Dalamud/Game/Gui/GameGui.cs b/Dalamud/Game/Gui/GameGui.cs index 3d17aad86..3b0f6eb66 100644 --- a/Dalamud/Game/Gui/GameGui.cs +++ b/Dalamud/Game/Gui/GameGui.cs @@ -32,7 +32,7 @@ namespace Dalamud.Game.Gui; [ServiceManager.EarlyLoadedService] internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui { - private static readonly ModuleLog Log = new("GameGui"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly GameGuiAddressResolver address; diff --git a/Dalamud/Game/Gui/NamePlate/NamePlateUpdateHandler.cs b/Dalamud/Game/Gui/NamePlate/NamePlateUpdateHandler.cs index a8c6ff3c1..e197e2360 100644 --- a/Dalamud/Game/Gui/NamePlate/NamePlateUpdateHandler.cs +++ b/Dalamud/Game/Gui/NamePlate/NamePlateUpdateHandler.cs @@ -427,8 +427,8 @@ internal unsafe class NamePlateUpdateHandler : INamePlateUpdateHandler /// public int VisibilityFlags { - get => ObjectData->VisibilityFlags; - set => ObjectData->VisibilityFlags = value; + get => this.ObjectData->VisibilityFlags; + set => this.ObjectData->VisibilityFlags = value; } /// diff --git a/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs b/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs index 1c78c871b..d7ab3080b 100644 --- a/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs +++ b/Dalamud/Game/Gui/PartyFinder/Types/JobFlagsExtensions.cs @@ -1,4 +1,5 @@ using Dalamud.Plugin.Services; + using Lumina.Excel.Sheets; namespace Dalamud.Game.Gui.PartyFinder.Types; diff --git a/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderSlot.cs b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderSlot.cs index 3d1e496fc..953e575d4 100644 --- a/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderSlot.cs +++ b/Dalamud/Game/Gui/PartyFinder/Types/PartyFinderSlot.cs @@ -23,23 +23,7 @@ public class PartyFinderSlot /// /// Gets a list of jobs that this slot is accepting. /// - public IReadOnlyCollection Accepting - { - get - { - if (this.listAccepting != null) - { - return this.listAccepting; - } - - this.listAccepting = Enum.GetValues(typeof(JobFlags)) - .Cast() - .Where(flag => this[flag]) - .ToArray(); - - return this.listAccepting; - } - } + public IReadOnlyCollection Accepting => this.listAccepting ??= Enum.GetValues().Where(flag => this[flag]).ToArray(); /// /// Tests if this slot is accepting a job. diff --git a/Dalamud/Game/Internal/DalamudAtkTweaks.cs b/Dalamud/Game/Internal/DalamudAtkTweaks.cs index 466401ef3..24fa88023 100644 --- a/Dalamud/Game/Internal/DalamudAtkTweaks.cs +++ b/Dalamud/Game/Internal/DalamudAtkTweaks.cs @@ -22,7 +22,7 @@ namespace Dalamud.Game.Internal; [ServiceManager.EarlyLoadedService] internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService { - private static readonly ModuleLog Log = new("DalamudAtkTweaks"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly Hook hookAgentHudOpenSystemMenu; diff --git a/Dalamud/Game/Inventory/GameInventory.cs b/Dalamud/Game/Inventory/GameInventory.cs index 5390c2707..2cfacfad0 100644 --- a/Dalamud/Game/Inventory/GameInventory.cs +++ b/Dalamud/Game/Inventory/GameInventory.cs @@ -18,15 +18,15 @@ namespace Dalamud.Game.Inventory; [ServiceManager.EarlyLoadedService] internal class GameInventory : IInternalDisposableService { - private readonly List subscribersPendingChange = new(); - private readonly List subscribers = new(); + private readonly List subscribersPendingChange = []; + private readonly List subscribers = []; - private readonly List addedEvents = new(); - private readonly List removedEvents = new(); - private readonly List changedEvents = new(); - private readonly List movedEvents = new(); - private readonly List splitEvents = new(); - private readonly List mergedEvents = new(); + private readonly List addedEvents = []; + private readonly List removedEvents = []; + private readonly List changedEvents = []; + private readonly List movedEvents = []; + private readonly List splitEvents = []; + private readonly List mergedEvents = []; [ServiceManager.ServiceDependency] private readonly Framework framework = Service.Get(); @@ -151,7 +151,7 @@ internal class GameInventory : IInternalDisposableService bool isNew; lock (this.subscribersPendingChange) { - isNew = this.subscribersPendingChange.Any() && !this.subscribers.Any(); + isNew = this.subscribersPendingChange.Count != 0 && this.subscribers.Count == 0; this.subscribers.Clear(); this.subscribers.AddRange(this.subscribersPendingChange); this.subscribersChanged = false; @@ -348,7 +348,7 @@ internal class GameInventory : IInternalDisposableService #pragma warning restore SA1015 internal class GameInventoryPluginScoped : IInternalDisposableService, IGameInventory { - private static readonly ModuleLog Log = new(nameof(GameInventoryPluginScoped)); + private static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceDependency] private readonly GameInventory gameInventoryService = Service.Get(); diff --git a/Dalamud/Game/Marketboard/MarketBoard.cs b/Dalamud/Game/Marketboard/MarketBoard.cs index 962e0010e..563a5bc4a 100644 --- a/Dalamud/Game/Marketboard/MarketBoard.cs +++ b/Dalamud/Game/Marketboard/MarketBoard.cs @@ -1,5 +1,3 @@ -using System.Linq; - using Dalamud.Game.Network.Internal; using Dalamud.Game.Network.Structures; using Dalamud.IoC; @@ -95,7 +93,7 @@ internal class MarketBoard : IInternalDisposableService, IMarketBoard #pragma warning restore SA1015 internal class MarketBoardPluginScoped : IInternalDisposableService, IMarketBoard { - private static readonly ModuleLog Log = new(nameof(MarketBoardPluginScoped)); + private static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceDependency] private readonly MarketBoard marketBoardService = Service.Get(); diff --git a/Dalamud/Game/NativeWrapper/AtkValuePtr.cs b/Dalamud/Game/NativeWrapper/AtkValuePtr.cs index a47483a66..b274d388b 100644 --- a/Dalamud/Game/NativeWrapper/AtkValuePtr.cs +++ b/Dalamud/Game/NativeWrapper/AtkValuePtr.cs @@ -89,7 +89,7 @@ public readonly unsafe struct AtkValuePtr(nint address) : IEquatable public unsafe bool TryGet([NotNullWhen(true)] out T? result) where T : struct { - object? value = this.GetValue(); + var value = this.GetValue(); if (value is T typed) { result = typed; diff --git a/Dalamud/Game/Network/GameNetwork.cs b/Dalamud/Game/Network/GameNetwork.cs index be464ef34..b8c91b235 100644 --- a/Dalamud/Game/Network/GameNetwork.cs +++ b/Dalamud/Game/Network/GameNetwork.cs @@ -2,9 +2,6 @@ using System.Runtime.InteropServices; using Dalamud.Configuration.Internal; using Dalamud.Hooking; -using Dalamud.IoC; -using Dalamud.IoC.Internal; -using Dalamud.Plugin.Services; using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.Network; diff --git a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs index 7ecb9c397..67769e4ca 100644 --- a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs +++ b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Net.Http; using System.Text; using System.Threading.Tasks; @@ -8,6 +7,7 @@ using Dalamud.Game.Network.Structures; using Dalamud.Networking.Http; using Newtonsoft.Json; + using Serilog; namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis; @@ -64,7 +64,7 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader PricePerUnit = marketBoardItemListing.PricePerUnit, Quantity = marketBoardItemListing.ItemQuantity, RetainerCity = marketBoardItemListing.RetainerCityId, - Materia = new List(), + Materia = [], }; #pragma warning restore CS0618 // Type or member is obsolete diff --git a/Dalamud/Game/Network/Internal/NetworkHandlers.cs b/Dalamud/Game/Network/Internal/NetworkHandlers.cs index 6a6d73b33..5ca7da54a 100644 --- a/Dalamud/Game/Network/Internal/NetworkHandlers.cs +++ b/Dalamud/Game/Network/Internal/NetworkHandlers.cs @@ -33,7 +33,7 @@ namespace Dalamud.Game.Network.Internal; [ServiceManager.EarlyLoadedService] internal unsafe class NetworkHandlers : IInternalDisposableService { - private readonly IMarketBoardUploader uploader; + private readonly UniversalisMarketBoardUploader uploader; private readonly IDisposable handleMarketBoardItemRequest; private readonly IDisposable handleMarketTaxRates; @@ -419,7 +419,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService private IDisposable HandleMarketBoardItemRequest() { - void LogStartObserved(MarketBoardItemRequest request) + static void LogStartObserved(MarketBoardItemRequest request) { Log.Verbose("Observed start of request for item with {NumListings} expected listings", request.AmountToArrive); } @@ -448,7 +448,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService private void UploadMarketBoardData( MarketBoardItemRequest request, (uint CatalogId, ICollection Sales) sales, - ICollection listings, + List listings, ulong uploaderId, uint worldId) { diff --git a/Dalamud/Game/SigScanner.cs b/Dalamud/Game/SigScanner.cs index 262e98fa5..81fb8a3a3 100644 --- a/Dalamud/Game/SigScanner.cs +++ b/Dalamud/Game/SigScanner.cs @@ -11,7 +11,9 @@ using System.Threading; using Dalamud.Plugin.Services; using Iced.Intel; + using Newtonsoft.Json; + using Serilog; namespace Dalamud.Game; diff --git a/Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs b/Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs index f05c15263..d16b3b9b3 100644 --- a/Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs +++ b/Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs @@ -48,7 +48,7 @@ namespace Dalamud.Game.Text.Evaluator; [ResolveVia] internal class SeStringEvaluator : IServiceType, ISeStringEvaluator { - private static readonly ModuleLog Log = new("SeStringEvaluator"); + private static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceDependency] private readonly ClientState.ClientState clientState = Service.Get(); @@ -244,154 +244,67 @@ internal class SeStringEvaluator : IServiceType, ISeStringEvaluator // if (context.HandlePayload(payload, in context)) // return true; - switch (payload.MacroCode) + return payload.MacroCode switch { - case MacroCode.SetResetTime: - return this.TryResolveSetResetTime(in context, payload); - - case MacroCode.SetTime: - return this.TryResolveSetTime(in context, payload); - - case MacroCode.If: - return this.TryResolveIf(in context, payload); - - case MacroCode.Switch: - return this.TryResolveSwitch(in context, payload); - - case MacroCode.SwitchPlatform: - return this.TryResolveSwitchPlatform(in context, payload); - - case MacroCode.PcName: - return this.TryResolvePcName(in context, payload); - - case MacroCode.IfPcGender: - return this.TryResolveIfPcGender(in context, payload); - - case MacroCode.IfPcName: - return this.TryResolveIfPcName(in context, payload); - - // case MacroCode.Josa: - // case MacroCode.Josaro: - - case MacroCode.IfSelf: - return this.TryResolveIfSelf(in context, payload); - - // case MacroCode.NewLine: // pass through - // case MacroCode.Wait: // pass through - // case MacroCode.Icon: // pass through - - case MacroCode.Color: - return this.TryResolveColor(in context, payload); - - case MacroCode.EdgeColor: - return this.TryResolveEdgeColor(in context, payload); - - case MacroCode.ShadowColor: - return this.TryResolveShadowColor(in context, payload); - - // case MacroCode.SoftHyphen: // pass through - // case MacroCode.Key: - // case MacroCode.Scale: - - case MacroCode.Bold: - return this.TryResolveBold(in context, payload); - - case MacroCode.Italic: - return this.TryResolveItalic(in context, payload); - - // case MacroCode.Edge: - // case MacroCode.Shadow: - // case MacroCode.NonBreakingSpace: // pass through - // case MacroCode.Icon2: // pass through - // case MacroCode.Hyphen: // pass through - - case MacroCode.Num: - return this.TryResolveNum(in context, payload); - - case MacroCode.Hex: - return this.TryResolveHex(in context, payload); - - case MacroCode.Kilo: - return this.TryResolveKilo(in context, payload); - - // case MacroCode.Byte: - - case MacroCode.Sec: - return this.TryResolveSec(in context, payload); - - // case MacroCode.Time: - - case MacroCode.Float: - return this.TryResolveFloat(in context, payload); - - // case MacroCode.Link: // pass through - - case MacroCode.Sheet: - return this.TryResolveSheet(in context, payload); - - case MacroCode.SheetSub: - return this.TryResolveSheetSub(in context, payload); - - case MacroCode.String: - return this.TryResolveString(in context, payload); - - case MacroCode.Caps: - return this.TryResolveCaps(in context, payload); - - case MacroCode.Head: - return this.TryResolveHead(in context, payload); - - case MacroCode.Split: - return this.TryResolveSplit(in context, payload); - - case MacroCode.HeadAll: - return this.TryResolveHeadAll(in context, payload); - - case MacroCode.Fixed: - return this.TryResolveFixed(in context, payload); - - case MacroCode.Lower: - return this.TryResolveLower(in context, payload); - - case MacroCode.JaNoun: - return this.TryResolveNoun(ClientLanguage.Japanese, in context, payload); - - case MacroCode.EnNoun: - return this.TryResolveNoun(ClientLanguage.English, in context, payload); - - case MacroCode.DeNoun: - return this.TryResolveNoun(ClientLanguage.German, in context, payload); - - case MacroCode.FrNoun: - return this.TryResolveNoun(ClientLanguage.French, in context, payload); - - // case MacroCode.ChNoun: - - case MacroCode.LowerHead: - return this.TryResolveLowerHead(in context, payload); - - case MacroCode.ColorType: - return this.TryResolveColorType(in context, payload); - - case MacroCode.EdgeColorType: - return this.TryResolveEdgeColorType(in context, payload); - - // case MacroCode.Ruby: - - case MacroCode.Digit: - return this.TryResolveDigit(in context, payload); - - case MacroCode.Ordinal: - return this.TryResolveOrdinal(in context, payload); - - // case MacroCode.Sound: // pass through - - case MacroCode.LevelPos: - return this.TryResolveLevelPos(in context, payload); - - default: - return false; - } + MacroCode.SetResetTime => this.TryResolveSetResetTime(in context, payload), + MacroCode.SetTime => this.TryResolveSetTime(in context, payload), + MacroCode.If => this.TryResolveIf(in context, payload), + MacroCode.Switch => this.TryResolveSwitch(in context, payload), + MacroCode.SwitchPlatform => this.TryResolveSwitchPlatform(in context, payload), + MacroCode.PcName => this.TryResolvePcName(in context, payload), + MacroCode.IfPcGender => this.TryResolveIfPcGender(in context, payload), + MacroCode.IfPcName => this.TryResolveIfPcName(in context, payload), + // MacroCode.Josa + // MacroCode.Josaro + MacroCode.IfSelf => this.TryResolveIfSelf(in context, payload), + // MacroCode.NewLine (pass through) + // MacroCode.Wait (pass through) + // MacroCode.Icon (pass through) + MacroCode.Color => this.TryResolveColor(in context, payload), + MacroCode.EdgeColor => this.TryResolveEdgeColor(in context, payload), + MacroCode.ShadowColor => this.TryResolveShadowColor(in context, payload), + // MacroCode.SoftHyphen (pass through) + // MacroCode.Key + // MacroCode.Scale + MacroCode.Bold => this.TryResolveBold(in context, payload), + MacroCode.Italic => this.TryResolveItalic(in context, payload), + // MacroCode.Edge + // MacroCode.Shadow + // MacroCode.NonBreakingSpace (pass through) + // MacroCode.Icon2 (pass through) + // MacroCode.Hyphen (pass through) + MacroCode.Num => this.TryResolveNum(in context, payload), + MacroCode.Hex => this.TryResolveHex(in context, payload), + MacroCode.Kilo => this.TryResolveKilo(in context, payload), + // MacroCode.Byte + MacroCode.Sec => this.TryResolveSec(in context, payload), + // MacroCode.Time + MacroCode.Float => this.TryResolveFloat(in context, payload), + // MacroCode.Link (pass through) + MacroCode.Sheet => this.TryResolveSheet(in context, payload), + MacroCode.SheetSub => this.TryResolveSheetSub(in context, payload), + MacroCode.String => this.TryResolveString(in context, payload), + MacroCode.Caps => this.TryResolveCaps(in context, payload), + MacroCode.Head => this.TryResolveHead(in context, payload), + MacroCode.Split => this.TryResolveSplit(in context, payload), + MacroCode.HeadAll => this.TryResolveHeadAll(in context, payload), + MacroCode.Fixed => this.TryResolveFixed(in context, payload), + MacroCode.Lower => this.TryResolveLower(in context, payload), + MacroCode.JaNoun => this.TryResolveNoun(ClientLanguage.Japanese, in context, payload), + MacroCode.EnNoun => this.TryResolveNoun(ClientLanguage.English, in context, payload), + MacroCode.DeNoun => this.TryResolveNoun(ClientLanguage.German, in context, payload), + MacroCode.FrNoun => this.TryResolveNoun(ClientLanguage.French, in context, payload), + // MacroCode.ChNoun + MacroCode.LowerHead => this.TryResolveLowerHead(in context, payload), + MacroCode.ColorType => this.TryResolveColorType(in context, payload), + MacroCode.EdgeColorType => this.TryResolveEdgeColorType(in context, payload), + // MacroCode.Ruby + MacroCode.Digit => this.TryResolveDigit(in context, payload), + MacroCode.Ordinal => this.TryResolveOrdinal(in context, payload), + // MacroCode.Sound (pass through) + MacroCode.LevelPos => this.TryResolveLevelPos(in context, payload), + _ => false, + }; } private unsafe bool TryResolveSetResetTime(in SeStringContext context, in ReadOnlySePayloadSpan payload) diff --git a/Dalamud/Game/Text/Noun/NounProcessor.cs b/Dalamud/Game/Text/Noun/NounProcessor.cs index 993d341df..c218bb26c 100644 --- a/Dalamud/Game/Text/Noun/NounProcessor.cs +++ b/Dalamud/Game/Text/Noun/NounProcessor.cs @@ -85,7 +85,7 @@ internal class NounProcessor : IServiceType private const int PronounColumnIdx = 6; private const int ArticleColumnIdx = 7; - private static readonly ModuleLog Log = new("NounProcessor"); + private static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceDependency] private readonly DataManager dataManager = Service.Get(); diff --git a/Dalamud/Game/Text/SeStringHandling/Payload.cs b/Dalamud/Game/Text/SeStringHandling/Payload.cs index c797c4a91..685ff517a 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payload.cs @@ -213,11 +213,10 @@ public abstract partial class Payload return payload; } - private static Payload DecodeText(BinaryReader reader) + private static TextPayload DecodeText(BinaryReader reader) { var payload = new TextPayload(); payload.DecodeImpl(reader, reader.BaseStream.Length); - return payload; } } @@ -382,7 +381,7 @@ public abstract partial class Payload { if (value < 0xCF) { - return new byte[] { (byte)(value + 1) }; + return [(byte)(value + 1)]; } var bytes = BitConverter.GetBytes(value); diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/IconPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/IconPayload.cs index 7963d422f..ad25de01d 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/IconPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/IconPayload.cs @@ -45,10 +45,10 @@ public class IconPayload : Payload { var indexBytes = MakeInteger((uint)this.Icon); var chunkLen = indexBytes.Length + 1; - var bytes = new List(new byte[] - { + var bytes = new List( + [ START_BYTE, (byte)SeStringChunkType.Icon, (byte)chunkLen, - }); + ]); bytes.AddRange(indexBytes); bytes.Add(END_BYTE); return bytes.ToArray(); diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs index 0c1f75a1d..20f05958f 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs @@ -8,6 +8,7 @@ using Dalamud.Utility; using Lumina.Excel; using Lumina.Excel.Sheets; + using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -172,7 +173,7 @@ public class ItemPayload : Payload }; bytes.AddRange(idBytes); // unk - bytes.AddRange(new byte[] { 0x02, 0x01 }); + bytes.AddRange([0x02, 0x01]); // Links don't have to include the name, but if they do, it requires additional work if (hasName) @@ -183,17 +184,17 @@ public class ItemPayload : Payload nameLen += 4; // space plus 3 bytes for HQ symbol } - bytes.AddRange(new byte[] - { + bytes.AddRange( + [ 0xFF, // unk (byte)nameLen, - }); + ]); bytes.AddRange(Encoding.UTF8.GetBytes(this.displayName)); if (this.IsHQ) { // space and HQ symbol - bytes.AddRange(new byte[] { 0x20, 0xEE, 0x80, 0xBC }); + bytes.AddRange([0x20, 0xEE, 0x80, 0xBC]); } } diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs index 7b672d07a..31cab41a1 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/MapLinkPayload.cs @@ -5,6 +5,7 @@ using Dalamud.Data; using Lumina.Excel; using Lumina.Excel.Sheets; + using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -174,7 +175,7 @@ public class MapLinkPayload : Payload bytes.AddRange(yBytes); // unk - bytes.AddRange(new byte[] { 0xFF, 0x01, END_BYTE }); + bytes.AddRange([0xFF, 0x01, END_BYTE]); return bytes.ToArray(); } diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/NewLinePayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/NewLinePayload.cs index 0b090b3d6..8072c87f5 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/NewLinePayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/NewLinePayload.cs @@ -7,7 +7,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads; /// public class NewLinePayload : Payload, ITextProvider { - private readonly byte[] bytes = { START_BYTE, (byte)SeStringChunkType.NewLine, 0x01, END_BYTE }; + private readonly byte[] bytes = [START_BYTE, (byte)SeStringChunkType.NewLine, 0x01, END_BYTE]; /// /// Gets an instance of NewLinePayload. diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/PartyFinderPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/PartyFinderPayload.cs index 0931ab03f..77ed7b8bc 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/PartyFinderPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/PartyFinderPayload.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using Lumina.Extensions; + using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads @@ -97,7 +98,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads reader.ReadByte(); // if the next byte is 0xF3 then this listing is limited to home world - byte nextByte = reader.ReadByte(); + var nextByte = reader.ReadByte(); switch (nextByte) { case (byte)PartyFinderLinkType.LimitedToHomeWorld: @@ -121,11 +122,11 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads // if the link type is notification, just use premade payload data since it's always the same. // i have no idea why it is formatted like this, but it is how it is. // note it is identical to the link terminator payload except the embedded info type is 0x08 - if (this.LinkType == PartyFinderLinkType.PartyFinderNotification) return new byte[] { 0x02, 0x27, 0x07, 0x08, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03, }; + if (this.LinkType == PartyFinderLinkType.PartyFinderNotification) return [0x02, 0x27, 0x07, 0x08, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03,]; // back to our regularly scheduled programming... var listingIDBytes = MakeInteger(this.ListingId); - bool isFlagSpecified = this.LinkType != PartyFinderLinkType.NotSpecified; + var isFlagSpecified = this.LinkType != PartyFinderLinkType.NotSpecified; var chunkLen = listingIDBytes.Length + 4; // 1 more byte for the type flag if it is specified diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/QuestPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/QuestPayload.cs index 19d494d8a..47947ccde 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/QuestPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/QuestPayload.cs @@ -5,6 +5,7 @@ using Dalamud.Data; using Lumina.Excel; using Lumina.Excel.Sheets; + using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -62,7 +63,7 @@ public class QuestPayload : Payload }; bytes.AddRange(idBytes); - bytes.AddRange(new byte[] { 0x01, 0x01, END_BYTE }); + bytes.AddRange([0x01, 0x01, END_BYTE]); return bytes.ToArray(); } diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/RawPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/RawPayload.cs index 02a7c113e..50464077b 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/RawPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/RawPayload.cs @@ -45,7 +45,7 @@ public class RawPayload : Payload /// /// Gets a fixed Payload representing a common link-termination sequence, found in many payload chains. /// - public static RawPayload LinkTerminator => new(new byte[] { 0x02, 0x27, 0x07, 0xCF, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03 }); + public static RawPayload LinkTerminator => new([0x02, 0x27, 0x07, 0xCF, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03]); /// public override PayloadType Type => PayloadType.Unknown; diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/SeHyphenPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/SeHyphenPayload.cs index 1739b9cda..48c55a5a8 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/SeHyphenPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/SeHyphenPayload.cs @@ -7,7 +7,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads; /// public class SeHyphenPayload : Payload, ITextProvider { - private readonly byte[] bytes = { START_BYTE, (byte)SeStringChunkType.SeHyphen, 0x01, END_BYTE }; + private readonly byte[] bytes = [START_BYTE, (byte)SeStringChunkType.SeHyphen, 0x01, END_BYTE]; /// /// Gets an instance of SeHyphenPayload. diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/StatusPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/StatusPayload.cs index d102dfab6..c17213f60 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/StatusPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/StatusPayload.cs @@ -5,6 +5,7 @@ using Dalamud.Data; using Lumina.Excel; using Lumina.Excel.Sheets; + using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -63,7 +64,7 @@ public class StatusPayload : Payload bytes.AddRange(idBytes); // unk - bytes.AddRange(new byte[] { 0x01, 0x01, 0xFF, 0x02, 0x20, END_BYTE }); + bytes.AddRange([0x01, 0x01, 0xFF, 0x02, 0x20, END_BYTE]); return bytes.ToArray(); } diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/UIForegroundPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/UIForegroundPayload.cs index bf360ce34..f161cff9d 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/UIForegroundPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/UIForegroundPayload.cs @@ -5,6 +5,7 @@ using Dalamud.Data; using Lumina.Excel; using Lumina.Excel.Sheets; + using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -95,10 +96,10 @@ public class UIForegroundPayload : Payload var colorBytes = MakeInteger(this.colorKey); var chunkLen = colorBytes.Length + 1; - var bytes = new List(new byte[] - { + var bytes = new List( + [ START_BYTE, (byte)SeStringChunkType.UIForeground, (byte)chunkLen, - }); + ]); bytes.AddRange(colorBytes); bytes.Add(END_BYTE); diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/UIGlowPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/UIGlowPayload.cs index e54427073..01c0d05d2 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/UIGlowPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/UIGlowPayload.cs @@ -5,6 +5,7 @@ using Dalamud.Data; using Lumina.Excel; using Lumina.Excel.Sheets; + using Newtonsoft.Json; namespace Dalamud.Game.Text.SeStringHandling.Payloads; @@ -98,10 +99,10 @@ public class UIGlowPayload : Payload var colorBytes = MakeInteger(this.colorKey); var chunkLen = colorBytes.Length + 1; - var bytes = new List(new byte[] - { + var bytes = new List( + [ START_BYTE, (byte)SeStringChunkType.UIGlow, (byte)chunkLen, - }); + ]); bytes.AddRange(colorBytes); bytes.Add(END_BYTE); diff --git a/Dalamud/Game/Text/SeStringHandling/SeString.cs b/Dalamud/Game/Text/SeStringHandling/SeString.cs index b94b05cac..b64a8bb67 100644 --- a/Dalamud/Game/Text/SeStringHandling/SeString.cs +++ b/Dalamud/Game/Text/SeStringHandling/SeString.cs @@ -28,7 +28,7 @@ public class SeString /// public SeString() { - this.Payloads = new List(); + this.Payloads = []; } /// diff --git a/Dalamud/Hooking/AsmHook.cs b/Dalamud/Hooking/AsmHook.cs index 09ae336dc..e6c9f61d8 100644 --- a/Dalamud/Hooking/AsmHook.cs +++ b/Dalamud/Hooking/AsmHook.cs @@ -169,9 +169,6 @@ public sealed class AsmHook : IDisposable, IDalamudHook /// private void CheckDisposed() { - if (this.IsDisposed) - { - throw new ObjectDisposedException(message: "Hook is already disposed", null); - } + ObjectDisposedException.ThrowIf(this.IsDisposed, this); } } diff --git a/Dalamud/Hooking/Hook.cs b/Dalamud/Hooking/Hook.cs index b8fd78b4f..c54a8f399 100644 --- a/Dalamud/Hooking/Hook.cs +++ b/Dalamud/Hooking/Hook.cs @@ -160,7 +160,7 @@ public abstract class Hook : IDalamudHook where T : Delegate (int)Math.Min(pDataDirectory->Size + pDataDirectory->VirtualAddress - importDescriptor.Name, moduleNameLowerWithNullTerminator.Length)); // Is this entry about the DLL that we're looking for? (Case insensitive) - if (currentDllNameWithNullTerminator.ToLowerInvariant() != moduleNameLowerWithNullTerminator) + if (!currentDllNameWithNullTerminator.Equals(moduleNameLowerWithNullTerminator, StringComparison.InvariantCultureIgnoreCase)) continue; if (isPe64) @@ -245,10 +245,7 @@ public abstract class Hook : IDalamudHook where T : Delegate /// protected void CheckDisposed() { - if (this.IsDisposed) - { - throw new ObjectDisposedException(message: "Hook is already disposed", null); - } + ObjectDisposedException.ThrowIf(this.IsDisposed, this); } private static unsafe IntPtr FromImportHelper32(IntPtr baseAddress, ref PeHeader.IMAGE_IMPORT_DESCRIPTOR desc, ref PeHeader.IMAGE_DATA_DIRECTORY dir, string functionName, uint hintOrOrdinal) diff --git a/Dalamud/Hooking/Internal/FunctionPointerVariableHook.cs b/Dalamud/Hooking/Internal/FunctionPointerVariableHook.cs index 8a53e664a..3d1073d2f 100644 --- a/Dalamud/Hooking/Internal/FunctionPointerVariableHook.cs +++ b/Dalamud/Hooking/Internal/FunctionPointerVariableHook.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using JetBrains.Annotations; + using Windows.Win32.System.Memory; using Win32Exception = System.ComponentModel.Win32Exception; @@ -45,7 +45,7 @@ internal unsafe class FunctionPointerVariableHook : Hook if (!HookManager.MultiHookTracker.TryGetValue(this.Address, out var indexList)) { - indexList = HookManager.MultiHookTracker[this.Address] = new List(); + indexList = HookManager.MultiHookTracker[this.Address] = []; } this.detourDelegate = detour; diff --git a/Dalamud/Hooking/Internal/GameInteropProviderPluginScoped.cs b/Dalamud/Hooking/Internal/GameInteropProviderPluginScoped.cs index 52d266335..583060d53 100644 --- a/Dalamud/Hooking/Internal/GameInteropProviderPluginScoped.cs +++ b/Dalamud/Hooking/Internal/GameInteropProviderPluginScoped.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Linq; using Dalamud.Game; @@ -8,6 +8,7 @@ using Dalamud.Plugin.Internal.Types; using Dalamud.Plugin.Services; using Dalamud.Utility; using Dalamud.Utility.Signatures; + using Serilog; namespace Dalamud.Hooking.Internal; @@ -25,7 +26,7 @@ internal class GameInteropProviderPluginScoped : IGameInteropProvider, IInternal private readonly LocalPlugin plugin; private readonly SigScanner scanner; - private readonly WeakConcurrentCollection trackedHooks = new(); + private readonly WeakConcurrentCollection trackedHooks = []; /// /// Initializes a new instance of the class. diff --git a/Dalamud/Hooking/Internal/HookManager.cs b/Dalamud/Hooking/Internal/HookManager.cs index 8f5dba583..83af01bf4 100644 --- a/Dalamud/Hooking/Internal/HookManager.cs +++ b/Dalamud/Hooking/Internal/HookManager.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; +using System.Threading; using Dalamud.Logging.Internal; using Dalamud.Memory; @@ -20,7 +21,7 @@ internal class HookManager : IInternalDisposableService /// /// Logger shared with . /// - internal static readonly ModuleLog Log = new("HM"); + internal static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceConstructor] private HookManager() @@ -30,7 +31,7 @@ internal class HookManager : IInternalDisposableService /// /// Gets sync root object for hook enabling/disabling. /// - internal static object HookEnableSyncRoot { get; } = new(); + internal static Lock HookEnableSyncRoot { get; } = new(); /// /// Gets a static list of tracked and registered hooks. diff --git a/Dalamud/Hooking/Internal/MinHookHook.cs b/Dalamud/Hooking/Internal/MinHookHook.cs index d4889ba11..9c7ec0f88 100644 --- a/Dalamud/Hooking/Internal/MinHookHook.cs +++ b/Dalamud/Hooking/Internal/MinHookHook.cs @@ -24,7 +24,7 @@ internal class MinHookHook : Hook where T : Delegate var unhooker = HookManager.RegisterUnhooker(this.Address); if (!HookManager.MultiHookTracker.TryGetValue(this.Address, out var indexList)) - indexList = HookManager.MultiHookTracker[this.Address] = new(); + indexList = HookManager.MultiHookTracker[this.Address] = []; var index = (ulong)indexList.Count; diff --git a/Dalamud/Hooking/WndProcHook/WndProcHookManager.cs b/Dalamud/Hooking/WndProcHook/WndProcHookManager.cs index 7c70a9f0b..82620eed8 100644 --- a/Dalamud/Hooking/WndProcHook/WndProcHookManager.cs +++ b/Dalamud/Hooking/WndProcHook/WndProcHookManager.cs @@ -17,10 +17,10 @@ namespace Dalamud.Hooking.WndProcHook; [ServiceManager.EarlyLoadedService] internal sealed class WndProcHookManager : IInternalDisposableService { - private static readonly ModuleLog Log = new(nameof(WndProcHookManager)); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly Hook dispatchMessageWHook; - private readonly Dictionary wndProcOverrides = new(); + private readonly Dictionary wndProcOverrides = []; private HWND mainWindowHwnd; diff --git a/Dalamud/Interface/ColorHelpers.cs b/Dalamud/Interface/ColorHelpers.cs index a3ae6799e..dd56f3d14 100644 --- a/Dalamud/Interface/ColorHelpers.cs +++ b/Dalamud/Interface/ColorHelpers.cs @@ -56,11 +56,10 @@ public static class ColorHelpers var min = Math.Min(r, Math.Min(g, b)); var h = max; - var s = max; var v = max; var d = max - min; - s = max == 0 ? 0 : d / max; + var s = max == 0 ? 0 : d / max; if (max == min) { diff --git a/Dalamud/Interface/Components/ImGuiComponents.HelpMarker.cs b/Dalamud/Interface/Components/ImGuiComponents.HelpMarker.cs index 57a4bd150..0d919cf6e 100644 --- a/Dalamud/Interface/Components/ImGuiComponents.HelpMarker.cs +++ b/Dalamud/Interface/Components/ImGuiComponents.HelpMarker.cs @@ -1,5 +1,6 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Common.Math; namespace Dalamud.Interface.Components; diff --git a/Dalamud/Interface/DragDrop/DragDropManager.cs b/Dalamud/Interface/DragDrop/DragDropManager.cs index 4375ddea9..504bdc716 100644 --- a/Dalamud/Interface/DragDrop/DragDropManager.cs +++ b/Dalamud/Interface/DragDrop/DragDropManager.cs @@ -5,6 +5,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface.Internal; using Dalamud.IoC; using Dalamud.IoC.Internal; + using Serilog; namespace Dalamud.Interface.DragDrop; diff --git a/Dalamud/Interface/DragDrop/DragDropTarget.cs b/Dalamud/Interface/DragDrop/DragDropTarget.cs index c6b66e7e8..8ac347c72 100644 --- a/Dalamud/Interface/DragDrop/DragDropTarget.cs +++ b/Dalamud/Interface/DragDrop/DragDropTarget.cs @@ -6,6 +6,7 @@ using System.Text; using Dalamud.Bindings.ImGui; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.DragDrop; diff --git a/Dalamud/Interface/FontAwesome/FontAwesomeExtensions.cs b/Dalamud/Interface/FontAwesome/FontAwesomeExtensions.cs index 2b8cb8c52..0bab4538a 100644 --- a/Dalamud/Interface/FontAwesome/FontAwesomeExtensions.cs +++ b/Dalamud/Interface/FontAwesome/FontAwesomeExtensions.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Dalamud.Utility; @@ -37,7 +37,7 @@ public static class FontAwesomeExtensions public static IEnumerable GetSearchTerms(this FontAwesomeIcon icon) { var searchTermsAttribute = icon.GetAttribute(); - return searchTermsAttribute == null ? new string[] { } : searchTermsAttribute.SearchTerms; + return searchTermsAttribute == null ? [] : searchTermsAttribute.SearchTerms; } /// @@ -48,6 +48,6 @@ public static class FontAwesomeExtensions public static IEnumerable GetCategories(this FontAwesomeIcon icon) { var categoriesAttribute = icon.GetAttribute(); - return categoriesAttribute == null ? new string[] { } : categoriesAttribute.Categories; + return categoriesAttribute == null ? [] : categoriesAttribute.Categories; } } diff --git a/Dalamud/Interface/FontAwesome/FontAwesomeHelpers.cs b/Dalamud/Interface/FontAwesome/FontAwesomeHelpers.cs index cf34d736e..51c896ad2 100644 --- a/Dalamud/Interface/FontAwesome/FontAwesomeHelpers.cs +++ b/Dalamud/Interface/FontAwesome/FontAwesomeHelpers.cs @@ -16,14 +16,7 @@ public static class FontAwesomeHelpers /// list of font awesome icons. public static List GetIcons() { - var icons = new List(); - foreach (var icon in Enum.GetValues(typeof(FontAwesomeIcon)).Cast().ToList()) - { - if (icon.IsObsolete()) continue; - icons.Add(icon); - } - - return icons; + return [.. Enum.GetValues().Where(icon => !icon.IsObsolete())]; } /// @@ -75,7 +68,7 @@ public static class FontAwesomeHelpers { var name = Enum.GetName(icon)?.ToLowerInvariant(); var searchTerms = icon.GetSearchTerms(); - if (name!.Contains(search.ToLowerInvariant()) || searchTerms.Contains(search.ToLowerInvariant())) + if (name!.Contains(search, StringComparison.InvariantCultureIgnoreCase) || searchTerms.Contains(search.ToLowerInvariant())) { result.Add(icon); } @@ -105,7 +98,7 @@ public static class FontAwesomeHelpers var name = Enum.GetName(icon)?.ToLowerInvariant(); var searchTerms = icon.GetSearchTerms(); var categories = icon.GetCategories(); - if ((name!.Contains(search.ToLowerInvariant()) || searchTerms.Contains(search.ToLowerInvariant())) && categories.Contains(category)) + if ((name!.Contains(search, StringComparison.InvariantCultureIgnoreCase) || searchTerms.Contains(search.ToLowerInvariant())) && categories.Contains(category)) { result.Add(icon); } diff --git a/Dalamud/Interface/FontIdentifier/DalamudAssetFontAndFamilyId.cs b/Dalamud/Interface/FontIdentifier/DalamudAssetFontAndFamilyId.cs index c531dced5..3778ea0de 100644 --- a/Dalamud/Interface/FontIdentifier/DalamudAssetFontAndFamilyId.cs +++ b/Dalamud/Interface/FontIdentifier/DalamudAssetFontAndFamilyId.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using Dalamud.Bindings.ImGui; using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Storage.Assets; + using Newtonsoft.Json; + using TerraFX.Interop.DirectX; namespace Dalamud.Interface.FontIdentifier; diff --git a/Dalamud/Interface/FontIdentifier/DalamudDefaultFontAndFamilyId.cs b/Dalamud/Interface/FontIdentifier/DalamudDefaultFontAndFamilyId.cs index c45cf256b..4666de54a 100644 --- a/Dalamud/Interface/FontIdentifier/DalamudDefaultFontAndFamilyId.cs +++ b/Dalamud/Interface/FontIdentifier/DalamudDefaultFontAndFamilyId.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using Dalamud.Bindings.ImGui; using Dalamud.Interface.ManagedFontAtlas; + using Newtonsoft.Json; + using TerraFX.Interop.DirectX; namespace Dalamud.Interface.FontIdentifier; diff --git a/Dalamud/Interface/FontIdentifier/GameFontAndFamilyId.cs b/Dalamud/Interface/FontIdentifier/GameFontAndFamilyId.cs index e294c8813..f19a2ec6a 100644 --- a/Dalamud/Interface/FontIdentifier/GameFontAndFamilyId.cs +++ b/Dalamud/Interface/FontIdentifier/GameFontAndFamilyId.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using Dalamud.Bindings.ImGui; using Dalamud.Interface.GameFonts; using Dalamud.Interface.ManagedFontAtlas; + using Newtonsoft.Json; + using TerraFX.Interop.DirectX; namespace Dalamud.Interface.FontIdentifier; diff --git a/Dalamud/Interface/FontIdentifier/IFontFamilyId.cs b/Dalamud/Interface/FontIdentifier/IFontFamilyId.cs index 991716f74..40780422a 100644 --- a/Dalamud/Interface/FontIdentifier/IFontFamilyId.cs +++ b/Dalamud/Interface/FontIdentifier/IFontFamilyId.cs @@ -36,26 +36,25 @@ public interface IFontFamilyId : IObjectWithLocalizableName /// /// The list of fonts. public static List ListDalamudFonts() => - new() - { + [ new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansJpMedium), new DalamudAssetFontAndFamilyId(DalamudAsset.InconsolataRegular), new DalamudAssetFontAndFamilyId(DalamudAsset.FontAwesomeFreeSolid), - }; + ]; /// /// Gets the list of Game-provided fonts. /// /// The list of fonts. - public static List ListGameFonts() => new() - { + public static List ListGameFonts() => + [ new GameFontAndFamilyId(GameFontFamily.Axis), new GameFontAndFamilyId(GameFontFamily.Jupiter), new GameFontAndFamilyId(GameFontFamily.JupiterNumeric), new GameFontAndFamilyId(GameFontFamily.Meidinger), new GameFontAndFamilyId(GameFontFamily.MiedingerMid), new GameFontAndFamilyId(GameFontFamily.TrumpGothic), - }; + ]; /// /// Gets the list of System-provided fonts. diff --git a/Dalamud/Interface/FontIdentifier/SingleFontSpec.cs b/Dalamud/Interface/FontIdentifier/SingleFontSpec.cs index 070b1c1e1..b1c03f9dd 100644 --- a/Dalamud/Interface/FontIdentifier/SingleFontSpec.cs +++ b/Dalamud/Interface/FontIdentifier/SingleFontSpec.cs @@ -6,6 +6,7 @@ using System.Text; using Dalamud.Bindings.ImGui; using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.Utility; + using Newtonsoft.Json; namespace Dalamud.Interface.FontIdentifier; diff --git a/Dalamud/Interface/FontIdentifier/SystemFontFamilyId.cs b/Dalamud/Interface/FontIdentifier/SystemFontFamilyId.cs index 83a5e810d..60e20fb6f 100644 --- a/Dalamud/Interface/FontIdentifier/SystemFontFamilyId.cs +++ b/Dalamud/Interface/FontIdentifier/SystemFontFamilyId.cs @@ -83,7 +83,7 @@ public sealed class SystemFontFamilyId : IFontFamilyId else if (candidates.Any(x => x.Style == (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL)) candidates.RemoveAll(x => x.Style != (int)DWRITE_FONT_STYLE.DWRITE_FONT_STYLE_NORMAL); - if (!candidates.Any()) + if (candidates.Count == 0) return 0; for (var i = 0; i < this.Fonts.Count; i++) @@ -117,7 +117,7 @@ public sealed class SystemFontFamilyId : IFontFamilyId return new(IObjectWithLocalizableName.GetLocaleNames(fn)); } - private unsafe IReadOnlyList GetFonts() + private unsafe List GetFonts() { using var dwf = default(ComPtr); fixed (Guid* piid = &IID.IID_IDWriteFactory) diff --git a/Dalamud/Interface/FontIdentifier/SystemFontId.cs b/Dalamud/Interface/FontIdentifier/SystemFontId.cs index 8401f4c79..45885a9a8 100644 --- a/Dalamud/Interface/FontIdentifier/SystemFontId.cs +++ b/Dalamud/Interface/FontIdentifier/SystemFontId.cs @@ -5,7 +5,9 @@ using System.Linq; using Dalamud.Bindings.ImGui; using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Utility; + using Newtonsoft.Json; + using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; diff --git a/Dalamud/Interface/GameFonts/FdtReader.cs b/Dalamud/Interface/GameFonts/FdtReader.cs index 0e8f3fb59..6f6aaea25 100644 --- a/Dalamud/Interface/GameFonts/FdtReader.cs +++ b/Dalamud/Interface/GameFonts/FdtReader.cs @@ -43,12 +43,12 @@ public class FdtReader /// /// Gets all the glyphs defined in this file. /// - public List Glyphs { get; init; } = new(); + public List Glyphs { get; init; } = []; /// /// Gets all the kerning entries defined in this file. /// - public List Distances { get; init; } = new(); + public List Distances { get; init; } = []; /// /// Finds the glyph index for the corresponding codepoint. @@ -269,7 +269,7 @@ public class FdtReader /// /// Mapping of texture channel index to byte index. /// - public static readonly int[] TextureChannelOrder = { 2, 1, 0, 3 }; + public static readonly int[] TextureChannelOrder = [2, 1, 0, 3]; /// /// Integer representation of a Unicode character in UTF-8 in reverse order, read in little endian. diff --git a/Dalamud/Interface/GameFonts/GameFontLayoutPlan.cs b/Dalamud/Interface/GameFonts/GameFontLayoutPlan.cs index 5b0fe100b..126e7601f 100644 --- a/Dalamud/Interface/GameFonts/GameFontLayoutPlan.cs +++ b/Dalamud/Interface/GameFonts/GameFontLayoutPlan.cs @@ -200,30 +200,25 @@ public class GameFontLayoutPlan return false; // TODO: Whatever - switch (char.GetUnicodeCategory((char)this.Codepoint)) - { - case System.Globalization.UnicodeCategory.SpaceSeparator: - case System.Globalization.UnicodeCategory.LineSeparator: - case System.Globalization.UnicodeCategory.ParagraphSeparator: - case System.Globalization.UnicodeCategory.Control: - case System.Globalization.UnicodeCategory.Format: - case System.Globalization.UnicodeCategory.Surrogate: - case System.Globalization.UnicodeCategory.PrivateUse: - case System.Globalization.UnicodeCategory.ConnectorPunctuation: - case System.Globalization.UnicodeCategory.DashPunctuation: - case System.Globalization.UnicodeCategory.OpenPunctuation: - case System.Globalization.UnicodeCategory.ClosePunctuation: - case System.Globalization.UnicodeCategory.InitialQuotePunctuation: - case System.Globalization.UnicodeCategory.FinalQuotePunctuation: - case System.Globalization.UnicodeCategory.OtherPunctuation: - case System.Globalization.UnicodeCategory.MathSymbol: - case System.Globalization.UnicodeCategory.ModifierSymbol: - case System.Globalization.UnicodeCategory.OtherSymbol: - case System.Globalization.UnicodeCategory.OtherNotAssigned: - return true; - } - - return false; + return char.GetUnicodeCategory((char)this.Codepoint) + is System.Globalization.UnicodeCategory.SpaceSeparator + or System.Globalization.UnicodeCategory.LineSeparator + or System.Globalization.UnicodeCategory.ParagraphSeparator + or System.Globalization.UnicodeCategory.Control + or System.Globalization.UnicodeCategory.Format + or System.Globalization.UnicodeCategory.Surrogate + or System.Globalization.UnicodeCategory.PrivateUse + or System.Globalization.UnicodeCategory.ConnectorPunctuation + or System.Globalization.UnicodeCategory.DashPunctuation + or System.Globalization.UnicodeCategory.OpenPunctuation + or System.Globalization.UnicodeCategory.ClosePunctuation + or System.Globalization.UnicodeCategory.InitialQuotePunctuation + or System.Globalization.UnicodeCategory.FinalQuotePunctuation + or System.Globalization.UnicodeCategory.OtherPunctuation + or System.Globalization.UnicodeCategory.MathSymbol + or System.Globalization.UnicodeCategory.ModifierSymbol + or System.Globalization.UnicodeCategory.OtherSymbol + or System.Globalization.UnicodeCategory.OtherNotAssigned; } } } @@ -300,7 +295,7 @@ public class GameFontLayoutPlan elements.Add(new() { Codepoint = c, Glyph = this.fdt.GetGlyph(c), }); var lastBreakIndex = 0; - List lineBreakIndices = new() { 0 }; + List lineBreakIndices = [0]; for (var i = 1; i < elements.Count; i++) { var prev = elements[i - 1]; diff --git a/Dalamud/Interface/GlyphRangesJapanese.cs b/Dalamud/Interface/GlyphRangesJapanese.cs index 2773b9db5..2acf7f40e 100644 --- a/Dalamud/Interface/GlyphRangesJapanese.cs +++ b/Dalamud/Interface/GlyphRangesJapanese.cs @@ -8,8 +8,8 @@ public static class GlyphRangesJapanese /// /// Gets the unicode glyph ranges for the Japanese language. /// - public static ushort[] GlyphRanges => new ushort[] - { + public static ushort[] GlyphRanges => + [ 0x0020, 0x00FF, 0x0391, 0x03A1, 0x03A3, 0x03A9, 0x03B1, 0x03C1, 0x03C3, 0x03C9, 0x0401, 0x0401, 0x0410, 0x044F, 0x0451, 0x0451, 0x2000, 0x206F, 0x2103, 0x2103, 0x212B, 0x212B, 0x2190, 0x2193, 0x21D2, 0x21D2, 0x21D4, 0x21D4, 0x2200, 0x2200, 0x2202, 0x2203, 0x2207, 0x2208, 0x220B, 0x220B, 0x2212, 0x2212, 0x221A, 0x221A, 0x221D, 0x221E, 0x2220, 0x2220, 0x2227, 0x222C, 0x2234, 0x2235, @@ -524,5 +524,5 @@ public static class GlyphRangesJapanese 0x9F4E, 0x9F4F, 0x9F52, 0x9F52, 0x9F54, 0x9F54, 0x9F5F, 0x9F63, 0x9F66, 0x9F67, 0x9F6A, 0x9F6A, 0x9F6C, 0x9F6C, 0x9F72, 0x9F72, 0x9F76, 0x9F77, 0x9F8D, 0x9F8D, 0x9F95, 0x9F95, 0x9F9C, 0x9F9D, 0x9FA0, 0x9FA0, 0xFF01, 0xFF01, 0xFF03, 0xFF06, 0xFF08, 0xFF0C, 0xFF0E, 0xFF3B, 0xFF3D, 0xFF5D, 0xFF61, 0xFF9F, 0xFFE3, 0xFFE3, 0xFFE5, 0xFFE5, 0xFFFF, 0xFFFF, 0, - }; + ]; } diff --git a/Dalamud/Interface/ImGuiBackend/Dx11Win32Backend.cs b/Dalamud/Interface/ImGuiBackend/Dx11Win32Backend.cs index ea609828d..e3b98ec37 100644 --- a/Dalamud/Interface/ImGuiBackend/Dx11Win32Backend.cs +++ b/Dalamud/Interface/ImGuiBackend/Dx11Win32Backend.cs @@ -1,9 +1,4 @@ -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImGuizmo; @@ -14,8 +9,6 @@ using Dalamud.Interface.ImGuiBackend.InputHandler; using Dalamud.Interface.ImGuiBackend.Renderers; using Dalamud.Utility; -using Serilog; - using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; diff --git a/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.ViewportHandler.cs b/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.ViewportHandler.cs index fe83d58a9..c8d82648e 100644 --- a/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.ViewportHandler.cs +++ b/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.ViewportHandler.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; using Dalamud.Interface.ImGuiBackend.Helpers; using Dalamud.Utility; + using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; diff --git a/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.cs b/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.cs index 2eb4e4970..a6abbb862 100644 --- a/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.cs +++ b/Dalamud/Interface/ImGuiBackend/Renderers/Dx11Renderer.cs @@ -15,6 +15,7 @@ using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Textures.TextureWraps.Internal; using Dalamud.Interface.Utility; using Dalamud.Utility; + using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; @@ -30,7 +31,7 @@ namespace Dalamud.Interface.ImGuiBackend.Renderers; Justification = "Multiple fixed/using scopes")] internal unsafe partial class Dx11Renderer : IImGuiRenderer { - private readonly List fontTextures = new(); + private readonly List fontTextures = []; private readonly D3D_FEATURE_LEVEL featureLevel; private readonly ViewportHandler viewportHandler; private readonly nint renderNamePtr; @@ -398,10 +399,9 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer /// private void CreateFontsTexture() { - if (this.device.IsEmpty()) - throw new ObjectDisposedException(nameof(Dx11Renderer)); + ObjectDisposedException.ThrowIf(this.device.IsEmpty(), this); - if (this.fontTextures.Any()) + if (this.fontTextures.Count != 0) return; var io = ImGui.GetIO(); @@ -479,8 +479,7 @@ internal unsafe partial class Dx11Renderer : IImGuiRenderer /// private void EnsureDeviceObjects() { - if (this.device.IsEmpty()) - throw new ObjectDisposedException(nameof(Dx11Renderer)); + ObjectDisposedException.ThrowIf(this.device.IsEmpty(), this); var assembly = Assembly.GetExecutingAssembly(); diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.Files.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.Files.cs index e5b7fc15e..1bad08f08 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.Files.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.Files.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using Dalamud.Utility; @@ -11,7 +12,7 @@ namespace Dalamud.Interface.ImGuiFileDialog; /// public partial class FileDialog { - private readonly object filesLock = new(); + private readonly Lock filesLock = new(); private readonly DriveListLoader driveListLoader = new(); diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.Filters.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.Filters.cs index 85b380bee..46f264354 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.Filters.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.Filters.cs @@ -8,11 +8,12 @@ namespace Dalamud.Interface.ImGuiFileDialog; /// public partial class FileDialog { - private static Regex filterRegex = new(@"[^,{}]+(\{([^{}]*?)\})?", RegexOptions.Compiled); - - private List filters = new(); + private List filters = []; private FilterStruct selectedFilter; + [GeneratedRegex(@"[^,{}]+(\{([^{}]*?)\})?", RegexOptions.Compiled)] + private static partial Regex FilterRegex(); + private void ParseFilters(string filters) { // ".*,.cpp,.h,.hpp" @@ -22,13 +23,13 @@ public partial class FileDialog if (filters.Length == 0) return; var currentFilterFound = false; - var matches = filterRegex.Matches(filters); + var matches = FilterRegex().Matches(filters); foreach (Match m in matches) { var match = m.Value; var filter = default(FilterStruct); - if (match.Contains("{")) + if (match.Contains('{')) { var exts = m.Groups[2].Value; filter = new FilterStruct @@ -42,7 +43,7 @@ public partial class FileDialog filter = new FilterStruct { Filter = match, - CollectionFilters = new(), + CollectionFilters = [], }; } @@ -89,7 +90,7 @@ public partial class FileDialog foreach (var file in this.files) { var show = true; - if (!string.IsNullOrEmpty(this.searchBuffer) && !file.FileName.ToLowerInvariant().Contains(this.searchBuffer.ToLowerInvariant())) + if (!string.IsNullOrEmpty(this.searchBuffer) && !file.FileName.Contains(this.searchBuffer, StringComparison.InvariantCultureIgnoreCase)) { show = false; } diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.Helpers.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.Helpers.cs index 57844c48b..7e5363673 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.Helpers.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.Helpers.cs @@ -12,7 +12,7 @@ public partial class FileDialog private static string BytesToString(long byteCount) { - string[] suf = { " B", " KB", " MB", " GB", " TB" }; + string[] suf = [" B", " KB", " MB", " GB", " TB"]; if (byteCount == 0) return "0" + suf[0]; var bytes = Math.Abs(byteCount); diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs index 3c02f9559..ef886e957 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs @@ -54,7 +54,7 @@ public partial class FileDialog windowVisible = ImGui.Begin(name, ref this.visible, this.WindowFlags); } - bool wasClosed = false; + var wasClosed = false; if (windowVisible) { if (!this.visible) @@ -122,15 +122,15 @@ public partial class FileDialog { if (iconMap == null) { - iconMap = new(); - AddToIconMap(new[] { "mp4", "gif", "mov", "avi" }, FontAwesomeIcon.FileVideo, miscTextColor); - AddToIconMap(new[] { "pdf" }, FontAwesomeIcon.FilePdf, miscTextColor); - AddToIconMap(new[] { "png", "jpg", "jpeg", "tiff" }, FontAwesomeIcon.FileImage, imageTextColor); - AddToIconMap(new[] { "cs", "json", "cpp", "h", "py", "xml", "yaml", "js", "html", "css", "ts", "java" }, FontAwesomeIcon.FileCode, codeTextColor); - AddToIconMap(new[] { "txt", "md" }, FontAwesomeIcon.FileAlt, standardTextColor); - AddToIconMap(new[] { "zip", "7z", "gz", "tar" }, FontAwesomeIcon.FileArchive, miscTextColor); - AddToIconMap(new[] { "mp3", "m4a", "ogg", "wav" }, FontAwesomeIcon.FileAudio, miscTextColor); - AddToIconMap(new[] { "csv" }, FontAwesomeIcon.FileCsv, miscTextColor); + iconMap = []; + AddToIconMap(["mp4", "gif", "mov", "avi"], FontAwesomeIcon.FileVideo, miscTextColor); + AddToIconMap(["pdf"], FontAwesomeIcon.FilePdf, miscTextColor); + AddToIconMap(["png", "jpg", "jpeg", "tiff"], FontAwesomeIcon.FileImage, imageTextColor); + AddToIconMap(["cs", "json", "cpp", "h", "py", "xml", "yaml", "js", "html", "css", "ts", "java"], FontAwesomeIcon.FileCode, codeTextColor); + AddToIconMap(["txt", "md"], FontAwesomeIcon.FileAlt, standardTextColor); + AddToIconMap(["zip", "7z", "gz", "tar"], FontAwesomeIcon.FileArchive, miscTextColor); + AddToIconMap(["mp3", "m4a", "ogg", "wav"], FontAwesomeIcon.FileAudio, miscTextColor); + AddToIconMap(["csv"], FontAwesomeIcon.FileCsv, miscTextColor); } return iconMap.TryGetValue(ext.ToLowerInvariant(), out var icon) ? icon : new IconColorItem diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs index 3d8246ffd..e33fc2fc4 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs @@ -30,7 +30,7 @@ public partial class FileDialog private string currentPath; private string fileNameBuffer = string.Empty; - private List pathDecomposition = new(); + private List pathDecomposition = []; private bool pathClicked = true; private bool pathInputActivated = false; private string pathInputBuffer = string.Empty; @@ -46,12 +46,12 @@ public partial class FileDialog private string searchBuffer = string.Empty; private string lastSelectedFileName = string.Empty; - private List selectedFileNames = new(); + private List selectedFileNames = []; private float footerHeight = 0; private string selectedSideBar = string.Empty; - private List quickAccess = new(); + private List quickAccess = []; /// /// Initializes a new instance of the class. @@ -130,12 +130,12 @@ public partial class FileDialog { if (!this.flags.HasFlag(ImGuiFileDialogFlags.SelectOnly)) { - return new List { this.GetFilePathName() }; + return [this.GetFilePathName()]; } if (this.IsDirectoryMode() && this.selectedFileNames.Count == 0) { - return new List { this.GetFilePathName() }; // current directory + return [this.GetFilePathName()]; // current directory } var fullPaths = this.selectedFileNames.Where(x => !string.IsNullOrEmpty(x)).Select(x => Path.Combine(this.currentPath, x)); diff --git a/Dalamud/Interface/ImGuiFontChooserDialog/SingleFontChooserDialog.cs b/Dalamud/Interface/ImGuiFontChooserDialog/SingleFontChooserDialog.cs index 6a381f5b2..2abdd3403 100644 --- a/Dalamud/Interface/ImGuiFontChooserDialog/SingleFontChooserDialog.cs +++ b/Dalamud/Interface/ImGuiFontChooserDialog/SingleFontChooserDialog.cs @@ -13,6 +13,7 @@ using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.ManagedFontAtlas.Internals; using Dalamud.Interface.Utility; using Dalamud.Utility; + using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; @@ -31,10 +32,10 @@ public sealed class SingleFontChooserDialog : IDisposable private const float MaxFontSizePt = 127; - private static readonly List EmptyIFontList = new(); + private static readonly List EmptyIFontList = []; private static readonly (string Name, float Value)[] FontSizeList = - { + [ ("9.6", 9.6f), ("10", 10f), ("12", 12f), @@ -51,7 +52,7 @@ public sealed class SingleFontChooserDialog : IDisposable ("46", 46), ("68", 68), ("90", 90), - }; + ]; private static int counterStatic; @@ -1235,7 +1236,7 @@ public sealed class SingleFontChooserDialog : IDisposable } private void UpdateSelectedFamilyAndFontIndices( - IReadOnlyList fonts, + List fonts, string familyName, string fontName) { diff --git a/Dalamud/Interface/ImGuiNotification/Internal/NotificationManager.cs b/Dalamud/Interface/ImGuiNotification/Internal/NotificationManager.cs index 340763a55..1b6e7e59b 100644 --- a/Dalamud/Interface/ImGuiNotification/Internal/NotificationManager.cs +++ b/Dalamud/Interface/ImGuiNotification/Internal/NotificationManager.cs @@ -26,8 +26,8 @@ internal class NotificationManager : INotificationManager, IInternalDisposableSe [ServiceManager.ServiceDependency] private readonly DalamudConfiguration configuration = Service.Get(); - private readonly List notifications = new(); - private readonly ConcurrentBag pendingNotifications = new(); + private readonly List notifications = []; + private readonly ConcurrentBag pendingNotifications = []; private NotificationPositionChooser? positionChooser; diff --git a/Dalamud/Interface/ImGuiNotification/Notification.cs b/Dalamud/Interface/ImGuiNotification/Notification.cs index 4dcb10c17..ef6bb3da8 100644 --- a/Dalamud/Interface/ImGuiNotification/Notification.cs +++ b/Dalamud/Interface/ImGuiNotification/Notification.cs @@ -1,9 +1,5 @@ -using System.Threading.Tasks; - using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.Textures; -using Dalamud.Interface.Textures.TextureWraps; -using Serilog; namespace Dalamud.Interface.ImGuiNotification; /// Represents a blueprint for a notification. diff --git a/Dalamud/Interface/ImGuiNotification/NotificationUtilities.cs b/Dalamud/Interface/ImGuiNotification/NotificationUtilities.cs index 4f0830fa1..5ef3cf4ac 100644 --- a/Dalamud/Interface/ImGuiNotification/NotificationUtilities.cs +++ b/Dalamud/Interface/ImGuiNotification/NotificationUtilities.cs @@ -1,11 +1,9 @@ using System.IO; using System.Numerics; using System.Runtime.CompilerServices; -using System.Threading.Tasks; using Dalamud.Bindings.ImGui; using Dalamud.Game.Text; -using Dalamud.Interface.Internal; using Dalamud.Interface.Internal.Windows; using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.Textures; diff --git a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs index f161c1868..5a19f9a50 100644 --- a/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs +++ b/Dalamud/Interface/ImGuiSeStringRenderer/Internal/SeStringRenderer.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using System.Text; using BitFaster.Caching.Lru; + using Dalamud.Bindings.ImGui; using Dalamud.Data; using Dalamud.Game; @@ -12,8 +13,10 @@ using Dalamud.Game.Text.SeStringHandling; using Dalamud.Interface.ImGuiSeStringRenderer.Internal.TextProcessing; using Dalamud.Interface.Utility; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI; + using Lumina.Excel.Sheets; using Lumina.Text; using Lumina.Text.Parse; diff --git a/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawState.cs b/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawState.cs index dcbe123e7..ee03643ad 100644 --- a/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawState.cs +++ b/Dalamud/Interface/ImGuiSeStringRenderer/SeStringDrawState.cs @@ -7,6 +7,7 @@ using System.Text; using Dalamud.Bindings.ImGui; using Dalamud.Interface.ImGuiSeStringRenderer.Internal; using Dalamud.Interface.Utility; + using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; diff --git a/Dalamud/Interface/Internal/Asserts/AssertHandler.cs b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs index 276dddb57..fadf80406 100644 --- a/Dalamud/Interface/Internal/Asserts/AssertHandler.cs +++ b/Dalamud/Interface/Internal/Asserts/AssertHandler.cs @@ -21,7 +21,7 @@ internal class AssertHandler : IDisposable private const int HidePrintEvery = 500; private readonly HashSet ignoredAsserts = []; - private readonly Dictionary assertCounts = new(); + private readonly Dictionary assertCounts = []; // Store callback to avoid it from being GC'd private readonly AssertCallbackDelegate callback; diff --git a/Dalamud/Interface/Internal/DalamudCommands.cs b/Dalamud/Interface/Internal/DalamudCommands.cs index 3e4a5cec6..9812a4e6a 100644 --- a/Dalamud/Interface/Internal/DalamudCommands.cs +++ b/Dalamud/Interface/Internal/DalamudCommands.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using CheapLoc; + using Dalamud.Configuration.Internal; using Dalamud.Game; using Dalamud.Game.Command; @@ -11,7 +11,6 @@ using Dalamud.Game.Gui; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.Internal; using Dalamud.Utility; -using Serilog; namespace Dalamud.Interface.Internal; @@ -208,7 +207,7 @@ internal class DalamudCommands : IServiceType var chatGui = Service.Get(); var configuration = Service.Get(); - configuration.BadWords ??= new List(); + configuration.BadWords ??= []; if (configuration.BadWords.Count == 0) { @@ -227,7 +226,7 @@ internal class DalamudCommands : IServiceType var chatGui = Service.Get(); var configuration = Service.Get(); - configuration.BadWords ??= new List(); + configuration.BadWords ??= []; configuration.BadWords.RemoveAll(x => x == arguments); @@ -326,7 +325,7 @@ internal class DalamudCommands : IServiceType var configuration = Service.Get(); var localization = Service.Get(); - if (Localization.ApplicableLangCodes.Contains(arguments.ToLowerInvariant()) || arguments.ToLowerInvariant() == "en") + if (Localization.ApplicableLangCodes.Contains(arguments.ToLowerInvariant()) || arguments.Equals("en", StringComparison.InvariantCultureIgnoreCase)) { localization.SetupWithLangCode(arguments.ToLowerInvariant()); configuration.LanguageOverride = arguments.ToLowerInvariant(); diff --git a/Dalamud/Interface/Internal/DalamudIme.cs b/Dalamud/Interface/Internal/DalamudIme.cs index cdb976333..e5ff83ff8 100644 --- a/Dalamud/Interface/Internal/DalamudIme.cs +++ b/Dalamud/Interface/Internal/DalamudIme.cs @@ -74,7 +74,7 @@ internal sealed unsafe class DalamudIme : IInternalDisposableService private readonly ImGuiSetPlatformImeDataDelegate setPlatformImeDataDelegate; /// The candidates. - private readonly List<(string String, bool Supported)> candidateStrings = new(); + private readonly List<(string String, bool Supported)> candidateStrings = []; /// The selected imm component. private string compositionString = string.Empty; diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index 13e7ff3f7..43f6d6ce7 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Bindings.ImPlot; using Dalamud.Configuration.Internal; @@ -39,9 +40,11 @@ using Dalamud.Plugin.Internal; using Dalamud.Plugin.SelfTest.Internal; using Dalamud.Storage.Assets; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; + using Serilog.Events; namespace Dalamud.Interface.Internal; @@ -54,7 +57,7 @@ internal class DalamudInterface : IInternalDisposableService { private const float CreditsDarkeningMaxAlpha = 0.8f; - private static readonly ModuleLog Log = new("DUI"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly Dalamud dalamud; private readonly DalamudConfiguration configuration; @@ -779,7 +782,7 @@ internal class DalamudInterface : IInternalDisposableService if (ImGui.BeginMenu("Set log level..."u8)) { - foreach (var logLevel in Enum.GetValues(typeof(LogEventLevel)).Cast()) + foreach (var logLevel in Enum.GetValues()) { if (ImGui.MenuItem(logLevel + "##logLevelSwitch", (byte*)null, EntryPoint.LogLevelSwitch.MinimumLevel == logLevel)) { @@ -912,7 +915,7 @@ internal class DalamudInterface : IInternalDisposableService if (ImGui.MenuItem("Cause CLR fastfail"u8)) { - unsafe void CauseFastFail() + static unsafe void CauseFastFail() { // ReSharper disable once NotAccessedVariable var texture = Unsafe.AsRef((void*)0x12345678); diff --git a/Dalamud/Interface/Internal/DesignSystem/DalamudComponents.PluginPicker.cs b/Dalamud/Interface/Internal/DesignSystem/DalamudComponents.PluginPicker.cs index 33bcffd38..3a69d55ea 100644 --- a/Dalamud/Interface/Internal/DesignSystem/DalamudComponents.PluginPicker.cs +++ b/Dalamud/Interface/Internal/DesignSystem/DalamudComponents.PluginPicker.cs @@ -1,7 +1,8 @@ -using System.Linq; +using System.Linq; using System.Numerics; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; diff --git a/Dalamud/Interface/Internal/ImGuiClipboardFunctionProvider.cs b/Dalamud/Interface/Internal/ImGuiClipboardFunctionProvider.cs index b7bfd21f1..13623545c 100644 --- a/Dalamud/Interface/Internal/ImGuiClipboardFunctionProvider.cs +++ b/Dalamud/Interface/Internal/ImGuiClipboardFunctionProvider.cs @@ -3,10 +3,12 @@ using System.Runtime.InteropServices; using System.Text; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Game.Gui.Toast; using Dalamud.Interface.Utility; using Dalamud.Logging.Internal; + using TerraFX.Interop.Windows; using static TerraFX.Interop.Windows.Windows; @@ -34,7 +36,7 @@ namespace Dalamud.Interface.Internal; [ServiceManager.EarlyLoadedService] internal sealed unsafe class ImGuiClipboardFunctionProvider : IInternalDisposableService { - private static readonly ModuleLog Log = new(nameof(ImGuiClipboardFunctionProvider)); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly void* clipboardUserDataOriginal; private readonly void* setTextOriginal; private readonly void* getTextOriginal; diff --git a/Dalamud/Interface/Internal/ImGuiInputTextStatePtrExtensions.cs b/Dalamud/Interface/Internal/ImGuiInputTextStatePtrExtensions.cs index ab5fdaac8..e27c20d06 100644 --- a/Dalamud/Interface/Internal/ImGuiInputTextStatePtrExtensions.cs +++ b/Dalamud/Interface/Internal/ImGuiInputTextStatePtrExtensions.cs @@ -110,7 +110,7 @@ internal static unsafe class ImGuiInputTextStatePtrExtensions var text = new Span(self.TextW.Data, self.TextW.Size); if (pos != textLen) - text.Slice(pos, textLen - pos).CopyTo(text[(pos + newText.Length)..]); + text[pos..textLen].CopyTo(text[(pos + newText.Length)..]); newText.CopyTo(text[pos..]); self.Edited = true; diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 96fcb7dfd..9d75b6aaf 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -1,5 +1,4 @@ using System.Collections.Concurrent; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -9,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Game; @@ -35,7 +35,9 @@ using Dalamud.Logging.Internal; using Dalamud.Plugin.Services; using Dalamud.Utility; using Dalamud.Utility.Timing; + using JetBrains.Annotations; + using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; @@ -76,10 +78,10 @@ internal partial class InterfaceManager : IInternalDisposableService /// public const float DefaultFontSizePx = (DefaultFontSizePt * 4.0f) / 3.0f; - private static readonly ModuleLog Log = new("INTERFACE"); + private static readonly ModuleLog Log = ModuleLog.Create(); - private readonly ConcurrentBag deferredDisposeTextures = new(); - private readonly ConcurrentBag deferredDisposeDisposables = new(); + private readonly ConcurrentBag deferredDisposeTextures = []; + private readonly ConcurrentBag deferredDisposeDisposables = []; [ServiceManager.ServiceDependency] private readonly DalamudConfiguration dalamudConfiguration = Service.Get(); @@ -678,8 +680,7 @@ internal partial class InterfaceManager : IInternalDisposableService if (configuration.SavedStyles == null || configuration.SavedStyles.All(x => x.Name != StyleModelV1.DalamudStandard.Name)) { - configuration.SavedStyles = new List - { StyleModelV1.DalamudStandard, StyleModelV1.DalamudClassic }; + configuration.SavedStyles = [StyleModelV1.DalamudStandard, StyleModelV1.DalamudClassic]; configuration.ChosenStyle = StyleModelV1.DalamudStandard.Name; } else if (configuration.SavedStyles.Count == 1) diff --git a/Dalamud/Interface/Internal/PluginCategoryManager.cs b/Dalamud/Interface/Internal/PluginCategoryManager.cs index d3aea7f57..2b7f0f354 100644 --- a/Dalamud/Interface/Internal/PluginCategoryManager.cs +++ b/Dalamud/Interface/Internal/PluginCategoryManager.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using CheapLoc; + using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal.Types; @@ -58,8 +59,8 @@ internal class PluginCategoryManager private CategoryKind currentCategoryKind = CategoryKind.All; private bool isContentDirty; - private Dictionary mapPluginCategories = new(); - private List highlightedCategoryKinds = new(); + private Dictionary mapPluginCategories = []; + private List highlightedCategoryKinds = []; /// /// Type of category group. @@ -513,8 +514,7 @@ internal class PluginCategoryManager this.GroupKind = groupKind; this.nameFunc = nameFunc; - this.Categories = new(); - this.Categories.AddRange(categories); + this.Categories = [.. categories]; } /// diff --git a/Dalamud/Interface/Internal/UiDebug.cs b/Dalamud/Interface/Internal/UiDebug.cs index 82554995b..a79cc1880 100644 --- a/Dalamud/Interface/Internal/UiDebug.cs +++ b/Dalamud/Interface/Internal/UiDebug.cs @@ -11,7 +11,6 @@ using Dalamud.Utility; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI.Misc; using FFXIVClientStructs.FFXIV.Component.GUI; -using Lumina.Text.ReadOnly; // Customised version of https://github.com/aers/FFXIVUIDebug @@ -25,8 +24,8 @@ internal unsafe class UiDebug private const int UnitListCount = 18; private readonly bool[] selectedInList = new bool[UnitListCount]; - private readonly string[] listNames = new string[UnitListCount] - { + private readonly string[] listNames = + [ "Depth Layer 1", "Depth Layer 2", "Depth Layer 3", @@ -45,7 +44,7 @@ internal unsafe class UiDebug "Units 16", "Units 17", "Units 18", - }; + ]; private bool doingSearch; private string searchInput = string.Empty; @@ -557,7 +556,7 @@ internal unsafe class UiDebug var name = unitBase->NameString; if (searching) { - if (name == null || !name.ToLowerInvariant().Contains(searchStr.ToLowerInvariant())) continue; + if (name == null || !name.Contains(searchStr, StringComparison.InvariantCultureIgnoreCase)) continue; } noResults = false; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs index b31f74264..b5899e15f 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs @@ -2,10 +2,9 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Internal.UiDebug2.Utility; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; -using Dalamud.Memory; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Component.GUI; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs index 0b1dcb66c..6ff58d657 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs @@ -41,7 +41,7 @@ public unsafe partial class AddonTree { foreach (var t in from t in ClientStructsAssembly.GetTypes() where t.IsPublic - let xivAddonAttr = (AddonAttribute?)t.GetCustomAttribute(typeof(AddonAttribute), false) + let xivAddonAttr = t.GetCustomAttribute(false) where xivAddonAttr != null where xivAddonAttr.AddonIdentifiers.Contains(this.AddonName) select t) @@ -83,7 +83,7 @@ public unsafe partial class AddonTree foreach (var field in baseType.GetFields(Static | Public | NonPublic | Instance)) { - if (field.GetCustomAttribute(typeof(FieldOffsetAttribute)) is FieldOffsetAttribute offset) + if (field.GetCustomAttribute() is FieldOffsetAttribute offset) { try { diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs index 7cb2cc704..2e0874206 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs @@ -4,7 +4,6 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; -using Dalamud.Interface.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs index 98c7d9efe..e094c6d7a 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs @@ -3,6 +3,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Bindings.ImGui.ImGuiTableColumnFlags; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs index 922d226b6..9a51f1771 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs @@ -1,6 +1,7 @@ using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; + using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs index ae6f5fffa..13cad9fd0 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs @@ -5,6 +5,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; using Dalamud.Interface.Internal.UiDebug2.Utility; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Bindings.ImGui.ImGuiColorEditFlags; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs index 260ea4942..aa7ee9a63 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs @@ -2,8 +2,8 @@ using System.Numerics; using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using FFXIVClientStructs.FFXIV.Component.GUI; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs index 489135ed0..6844c8a6f 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs @@ -1,6 +1,5 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface.Internal.UiDebug2.Utility; -using Dalamud.Interface.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs index 418156811..f38bef400 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs @@ -5,8 +5,8 @@ using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; using Dalamud.Interface.Internal.UiDebug2.Utility; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Bindings.ImGui.ImGuiCol; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs index 1435335db..618517e62 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs @@ -8,6 +8,7 @@ using Dalamud.Interface.ImGuiSeStringRenderer; using Dalamud.Interface.Internal.UiDebug2.Utility; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Component.GUI; diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs index 21f4fb54a..af0e0f284 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs @@ -5,6 +5,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Client.Graphics; using FFXIVClientStructs.FFXIV.Component.GUI; diff --git a/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs b/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs index 2ea8fd5d2..3286df1b3 100644 --- a/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs +++ b/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs @@ -8,6 +8,7 @@ using Dalamud.Interface.Components; using Dalamud.Interface.Internal.UiDebug2.Browsing; using Dalamud.Interface.Internal.UiDebug2.Utility; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Component.GUI; using static System.Globalization.NumberFormatInfo; diff --git a/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs b/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs index da4b95256..88af38531 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs @@ -4,6 +4,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface.Internal.UiDebug2.Browsing; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; + using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Interface.Internal.UiDebug2.UiDebug2; diff --git a/Dalamud/Interface/Internal/UiDebug2/UiDebug2.Sidebar.cs b/Dalamud/Interface/Internal/UiDebug2/UiDebug2.Sidebar.cs index 210da896f..14da58d94 100644 --- a/Dalamud/Interface/Internal/UiDebug2/UiDebug2.Sidebar.cs +++ b/Dalamud/Interface/Internal/UiDebug2/UiDebug2.Sidebar.cs @@ -4,6 +4,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; diff --git a/Dalamud/Interface/Internal/UiDebug2/UiDebug2.cs b/Dalamud/Interface/Internal/UiDebug2/UiDebug2.cs index ce4c6dfeb..2aaef9256 100644 --- a/Dalamud/Interface/Internal/UiDebug2/UiDebug2.cs +++ b/Dalamud/Interface/Internal/UiDebug2/UiDebug2.cs @@ -7,6 +7,7 @@ using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using Dalamud.Logging.Internal; using Dalamud.Plugin.Services; + using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Bindings.ImGui.ImGuiWindowFlags; @@ -21,6 +22,9 @@ namespace Dalamud.Interface.Internal.UiDebug2; /// internal partial class UiDebug2 : IDisposable { + /// + internal static readonly ModuleLog Log = ModuleLog.Create(); + private readonly ElementSelector elementSelector; /// @@ -31,9 +35,6 @@ internal partial class UiDebug2 : IDisposable this.elementSelector = new(this); } - /// - internal static ModuleLog Log { get; set; } = new("UiDebug2"); - /// internal static IGameGui GameGui { get; set; } = Service.Get(); diff --git a/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs b/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs index da5f30e68..5c1e72aed 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs @@ -3,6 +3,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Client.Graphics; using static Dalamud.Bindings.ImGui.ImGuiCol; diff --git a/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs b/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs index 832c7f357..3af306daf 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs +++ b/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs @@ -4,6 +4,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; + using FFXIVClientStructs.FFXIV.Component.GUI; using static System.MathF; diff --git a/Dalamud/Interface/Internal/Windows/ChangelogWindow.cs b/Dalamud/Interface/Internal/Windows/ChangelogWindow.cs index 44626ba31..c67eebfec 100644 --- a/Dalamud/Interface/Internal/Windows/ChangelogWindow.cs +++ b/Dalamud/Interface/Internal/Windows/ChangelogWindow.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Numerics; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Game; @@ -22,6 +23,7 @@ using Dalamud.Plugin.Internal.AutoUpdate; using Dalamud.Plugin.Services; using Dalamud.Storage.Assets; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Client.UI; namespace Dalamud.Interface.Internal.Windows; @@ -85,7 +87,7 @@ internal sealed class ChangelogWindow : Window, IDisposable private AutoUpdateBehavior? chosenAutoUpdateBehavior; - private Dictionary currentFtueLevels = new(); + private Dictionary currentFtueLevels = []; private DateTime? isEligibleSince; private bool openedThroughEligibility; diff --git a/Dalamud/Interface/Internal/Windows/ColorDemoWindow.cs b/Dalamud/Interface/Internal/Windows/ColorDemoWindow.cs index 1bff1d5c1..564e8ca5e 100644 --- a/Dalamud/Interface/Internal/Windows/ColorDemoWindow.cs +++ b/Dalamud/Interface/Internal/Windows/ColorDemoWindow.cs @@ -5,7 +5,6 @@ using System.Reflection; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Colors; -using Dalamud.Interface.Utility; using Dalamud.Interface.Windowing; namespace Dalamud.Interface.Internal.Windows; diff --git a/Dalamud/Interface/Internal/Windows/ComponentDemoWindow.cs b/Dalamud/Interface/Internal/Windows/ComponentDemoWindow.cs index 9096d78de..61435f723 100644 --- a/Dalamud/Interface/Internal/Windows/ComponentDemoWindow.cs +++ b/Dalamud/Interface/Internal/Windows/ComponentDemoWindow.cs @@ -19,14 +19,14 @@ internal sealed class ComponentDemoWindow : Window private static readonly TimeSpan DefaultEasingTime = new(0, 0, 0, 1700); private readonly List<(string Name, Action Demo)> componentDemos; - private readonly IReadOnlyList easings = new Easing[] - { + private readonly IReadOnlyList easings = + [ new InSine(DefaultEasingTime), new OutSine(DefaultEasingTime), new InOutSine(DefaultEasingTime), new InCubic(DefaultEasingTime), new OutCubic(DefaultEasingTime), new InOutCubic(DefaultEasingTime), new InQuint(DefaultEasingTime), new OutQuint(DefaultEasingTime), new InOutQuint(DefaultEasingTime), new InCirc(DefaultEasingTime), new OutCirc(DefaultEasingTime), new InOutCirc(DefaultEasingTime), new InElastic(DefaultEasingTime), new OutElastic(DefaultEasingTime), new InOutElastic(DefaultEasingTime), - }; + ]; private int animationTimeMs = (int)DefaultEasingTime.TotalMilliseconds; private Vector4 defaultColor = ImGuiColors.DalamudOrange; @@ -42,14 +42,14 @@ internal sealed class ComponentDemoWindow : Window this.RespectCloseHotkey = false; - this.componentDemos = new() - { + this.componentDemos = + [ ("Test", ImGuiComponents.Test), ("HelpMarker", HelpMarkerDemo), ("IconButton", IconButtonDemo), ("TextWithLabel", TextWithLabelDemo), ("ColorPickerWithPalette", this.ColorPickerWithPaletteDemo), - }; + ]; } /// diff --git a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs index 74df500db..36b0883bb 100644 --- a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs +++ b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Numerics; -using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; @@ -22,6 +21,7 @@ using Dalamud.Interface.Windowing; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Services; using Dalamud.Utility; + using Serilog; using Serilog.Events; @@ -40,7 +40,7 @@ internal class ConsoleWindow : Window, IDisposable private readonly RollingList logText; private readonly RollingList filteredLogEntries; - private readonly List pluginFilters = new(); + private readonly List pluginFilters = []; private readonly DalamudConfiguration configuration; diff --git a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs index eb0589d59..dbc778614 100644 --- a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs @@ -8,6 +8,7 @@ using Dalamud.Interface.Internal.Windows.Data.Widgets; using Dalamud.Interface.Utility; using Dalamud.Interface.Windowing; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.Internal.Windows.Data; @@ -18,7 +19,7 @@ namespace Dalamud.Interface.Internal.Windows.Data; internal class DataWindow : Window, IDisposable { private readonly IDataWindowWidget[] modules = - { + [ new AddonInspectorWidget(), new AddonInspectorWidget2(), new AddonLifecycleWidget(), @@ -62,7 +63,7 @@ internal class DataWindow : Window, IDisposable new UiColorWidget(), new UldWidget(), new VfsWidget(), - }; + ]; private readonly IOrderedEnumerable orderedModules; diff --git a/Dalamud/Interface/Internal/Windows/Data/DataWindowWidgetExtensions.cs b/Dalamud/Interface/Internal/Windows/Data/DataWindowWidgetExtensions.cs index a81d3edf3..d286c4428 100644 --- a/Dalamud/Interface/Internal/Windows/Data/DataWindowWidgetExtensions.cs +++ b/Dalamud/Interface/Internal/Windows/Data/DataWindowWidgetExtensions.cs @@ -3,7 +3,6 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification.Internal; -using Dalamud.Interface.Utility; namespace Dalamud.Interface.Internal.Windows.Data; diff --git a/Dalamud/Interface/Internal/Windows/Data/GameInventoryTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/GameInventoryTestWidget.cs index 55f619e9f..2031c66c2 100644 --- a/Dalamud/Interface/Internal/Windows/Data/GameInventoryTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/GameInventoryTestWidget.cs @@ -5,9 +5,9 @@ using Dalamud.Configuration.Internal; using Dalamud.Game.Inventory; using Dalamud.Game.Inventory.InventoryEventArgTypes; using Dalamud.Interface.Colors; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Logging.Internal; + using Serilog.Events; namespace Dalamud.Interface.Internal.Windows.Data; @@ -17,14 +17,14 @@ namespace Dalamud.Interface.Internal.Windows.Data; /// internal class GameInventoryTestWidget : IDataWindowWidget { - private static readonly ModuleLog Log = new(nameof(GameInventoryTestWidget)); + private static readonly ModuleLog Log = ModuleLog.Create(); private GameInventoryPluginScoped? scoped; private bool standardEnabled; private bool rawEnabled; /// - public string[]? CommandShortcuts { get; init; } = { "gameinventorytest" }; + public string[]? CommandShortcuts { get; init; } = ["gameinventorytest"]; /// public string DisplayName { get; init; } = "GameInventory Test"; diff --git a/Dalamud/Interface/Internal/Windows/Data/WidgetUtil.cs b/Dalamud/Interface/Internal/Windows/Data/WidgetUtil.cs index bb8bd8ea1..58cc672e8 100644 --- a/Dalamud/Interface/Internal/Windows/Data/WidgetUtil.cs +++ b/Dalamud/Interface/Internal/Windows/Data/WidgetUtil.cs @@ -1,5 +1,4 @@ using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Utility; namespace Dalamud.Interface.Internal.Windows.Data; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget.cs index e11404dec..c8a747239 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget.cs @@ -8,7 +8,7 @@ internal class AddonInspectorWidget : IDataWindowWidget private UiDebug? addonInspector; /// - public string[]? CommandShortcuts { get; init; } = { "ai", "addoninspector" }; + public string[]? CommandShortcuts { get; init; } = ["ai", "addoninspector"]; /// public string DisplayName { get; init; } = "Addon Inspector"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonLifecycleWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonLifecycleWidget.cs index 4fb13b81a..0316cc84e 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonLifecycleWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonLifecycleWidget.cs @@ -19,7 +19,7 @@ public class AddonLifecycleWidget : IDataWindowWidget public string DisplayName { get; init; } = "Addon Lifecycle"; /// - [MemberNotNullWhen(true, "AddonLifecycle")] + [MemberNotNullWhen(true, nameof(AddonLifecycle))] public bool Ready { get; set; } private AddonLifecycle? AddonLifecycle { get; set; } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddressesWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddressesWidget.cs index 6f41fa46f..06c7ea393 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddressesWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddressesWidget.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Dalamud.Bindings.ImGui; using Dalamud.Game; @@ -15,7 +15,7 @@ internal class AddressesWidget : IDataWindowWidget private nint sigResult = nint.Zero; /// - public string[]? CommandShortcuts { get; init; } = { "address" }; + public string[]? CommandShortcuts { get; init; } = ["address"]; /// public string DisplayName { get; init; } = "Addresses"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs index cc5492228..f414a9423 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs @@ -12,7 +12,7 @@ internal class AetherytesWidget : IDataWindowWidget public bool Ready { get; set; } /// - public string[]? CommandShortcuts { get; init; } = { "aetherytes" }; + public string[]? CommandShortcuts { get; init; } = ["aetherytes"]; /// public string DisplayName { get; init; } = "Aetherytes"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AtkArrayDataBrowserWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AtkArrayDataBrowserWidget.cs index c3074e807..03f5ab32e 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AtkArrayDataBrowserWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AtkArrayDataBrowserWidget.cs @@ -3,8 +3,10 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; + using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; + using Lumina.Text.ReadOnly; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -32,7 +34,7 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget public bool Ready { get; set; } /// - public string[]? CommandShortcuts { get; init; } = { "atkarray" }; + public string[]? CommandShortcuts { get; init; } = ["atkarray"]; /// public string DisplayName { get; init; } = "Atk Array Data"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/BuddyListWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/BuddyListWidget.cs index 06dc1b11e..10efdbae1 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/BuddyListWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/BuddyListWidget.cs @@ -15,7 +15,7 @@ internal class BuddyListWidget : IDataWindowWidget public bool Ready { get; set; } /// - public string[]? CommandShortcuts { get; init; } = { "buddy", "buddylist" }; + public string[]? CommandShortcuts { get; init; } = ["buddy", "buddylist"]; /// public string DisplayName { get; init; } = "Buddy List"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/CommandWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/CommandWidget.cs index f5a521672..1082bf6ca 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/CommandWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/CommandWidget.cs @@ -2,7 +2,6 @@ using System.Linq; using Dalamud.Bindings.ImGui; using Dalamud.Game.Command; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -13,7 +12,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class CommandWidget : IDataWindowWidget { /// - public string[]? CommandShortcuts { get; init; } = { "command" }; + public string[]? CommandShortcuts { get; init; } = ["command"]; /// public string DisplayName { get; init; } = "Command"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ConditionWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ConditionWidget.cs index 6ecee48ed..e3a737a25 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ConditionWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ConditionWidget.cs @@ -1,4 +1,4 @@ -using Dalamud.Bindings.ImGui; +using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Conditions; using Dalamud.Utility; @@ -13,7 +13,7 @@ internal class ConditionWidget : IDataWindowWidget public bool Ready { get; set; } /// - public string[]? CommandShortcuts { get; init; } = { "condition" }; + public string[]? CommandShortcuts { get; init; } = ["condition"]; /// public string DisplayName { get; init; } = "Condition"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ConfigurationWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ConfigurationWidget.cs index f66b50fca..c6a3477ae 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ConfigurationWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ConfigurationWidget.cs @@ -1,4 +1,4 @@ -using Dalamud.Configuration.Internal; +using Dalamud.Configuration.Internal; using Dalamud.Utility; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -9,7 +9,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class ConfigurationWidget : IDataWindowWidget { /// - public string[]? CommandShortcuts { get; init; } = { "config", "configuration" }; + public string[]? CommandShortcuts { get; init; } = ["config", "configuration"]; /// public string DisplayName { get; init; } = "Configuration"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/DataShareWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/DataShareWidget.cs index 83db4ac6e..8c9774840 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/DataShareWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/DataShareWidget.cs @@ -11,6 +11,7 @@ using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Plugin.Ipc.Internal; + using Newtonsoft.Json; using Formatting = Newtonsoft.Json.Formatting; @@ -28,13 +29,13 @@ internal class DataShareWidget : IDataWindowWidget { private const ImGuiTabItemFlags NoCloseButton = (ImGuiTabItemFlags)(1 << 20); - private readonly List<(string Name, byte[]? Data)> dataView = new(); + private readonly List<(string Name, byte[]? Data)> dataView = []; private int nextTab = -1; private IReadOnlyDictionary? gates; private List? gatesSorted; /// - public string[]? CommandShortcuts { get; init; } = { "datashare" }; + public string[]? CommandShortcuts { get; init; } = ["datashare"]; /// public string DisplayName { get; init; } = "Data Share & Call Gate"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/DtrBarWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/DtrBarWidget.cs index 0a40c9be7..838f11632 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/DtrBarWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/DtrBarWidget.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using System.Threading; using Dalamud.Bindings.ImGui; @@ -21,7 +21,7 @@ internal class DtrBarWidget : IDataWindowWidget, IDisposable private CancellationTokenSource? loadTestThreadCt; /// - public string[]? CommandShortcuts { get; init; } = { "dtr", "dtrbar" }; + public string[]? CommandShortcuts { get; init; } = ["dtr", "dtrbar"]; /// public string DisplayName { get; init; } = "DTR Bar"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/FateTableWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/FateTableWidget.cs index 50ed79b3d..e241f157d 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/FateTableWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/FateTableWidget.cs @@ -1,7 +1,6 @@ using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Fates; using Dalamud.Interface.Textures.Internal; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -12,7 +11,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class FateTableWidget : IDataWindowWidget { /// - public string[]? CommandShortcuts { get; init; } = { "fate", "fatetable" }; + public string[]? CommandShortcuts { get; init; } = ["fate", "fatetable"]; /// public string DisplayName { get; init; } = "Fate Table"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/FlyTextWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/FlyTextWidget.cs index d20aa5cb1..7910daaec 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/FlyTextWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/FlyTextWidget.cs @@ -22,7 +22,7 @@ internal class FlyTextWidget : IDataWindowWidget private Vector4 flyColor = new(1, 0, 0, 1); /// - public string[]? CommandShortcuts { get; init; } = { "flytext" }; + public string[]? CommandShortcuts { get; init; } = ["flytext"]; /// public string DisplayName { get; init; } = "Fly Text"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs index ea4b80247..8beb437ac 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/FontAwesomeTestWidget.cs @@ -27,7 +27,7 @@ internal class FontAwesomeTestWidget : IDataWindowWidget private bool useFixedWidth = false; /// - public string[]? CommandShortcuts { get; init; } = { "fa", "fatest", "fontawesome" }; + public string[]? CommandShortcuts { get; init; } = ["fa", "fatest", "fontawesome"]; /// public string DisplayName { get; init; } = "Font Awesome Test"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs index c653e9185..32ad076db 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; @@ -15,6 +14,7 @@ using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.ManagedFontAtlas.Internals; using Dalamud.Interface.Utility; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -25,11 +25,11 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable { private static readonly string[] FontScaleModes = - { + [ nameof(FontScaleMode.Default), nameof(FontScaleMode.SkipHandling), nameof(FontScaleMode.UndoGlobalScale), - }; + ]; private ImVectorWrapper testStringBuffer; private IFontAtlas? privateAtlas; @@ -338,7 +338,7 @@ internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable return; - void TestSingle(ImFontPtr fontPtr, IFontHandle handle) + static void TestSingle(ImFontPtr fontPtr, IFontHandle handle) { var dim = ImGui.CalcTextSizeA(fontPtr, fontPtr.FontSize, float.MaxValue, 0f, "Test string"u8, out _); Log.Information($"{nameof(GamePrebakedFontsTestWidget)}: {handle} => {dim}"); diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs index 65e6cd3d6..ed1a4da5b 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs @@ -1,4 +1,4 @@ -using Dalamud.Bindings.ImGui; +using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.GamePad; using Dalamud.Utility; @@ -10,7 +10,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class GamepadWidget : IDataWindowWidget { /// - public string[]? CommandShortcuts { get; init; } = { "gamepad", "controller" }; + public string[]? CommandShortcuts { get; init; } = ["gamepad", "controller"]; /// public string DisplayName { get; init; } = "Gamepad"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs index 7a5a9c89b..09bd29851 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs @@ -12,7 +12,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class GaugeWidget : IDataWindowWidget { /// - public string[]? CommandShortcuts { get; init; } = { "gauge", "jobgauge", "job" }; + public string[]? CommandShortcuts { get; init; } = ["gauge", "jobgauge", "job"]; /// public string DisplayName { get; init; } = "Job Gauge"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs index f3e25caf8..ad06e12fd 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -6,8 +6,11 @@ using System.Threading.Tasks; using Dalamud.Bindings.ImGui; using Dalamud.Game; using Dalamud.Hooking; + using FFXIVClientStructs.FFXIV.Component.GUI; + using Serilog; + using Windows.Win32.Foundation; using Windows.Win32.UI.WindowsAndMessaging; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs index 0395f4c96..77ca7ec2b 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs @@ -33,7 +33,7 @@ public class IconBrowserWidget : IDataWindowWidget private Vector2 lastWindowSize = Vector2.Zero; /// - public string[]? CommandShortcuts { get; init; } = { "icon", "icons" }; + public string[]? CommandShortcuts { get; init; } = ["icon", "icons"]; /// public string DisplayName { get; init; } = "Icon Browser"; @@ -269,7 +269,7 @@ public class IconBrowserWidget : IDataWindowWidget if (this.valueRange is not null) return; - this.valueRange = new(); + this.valueRange = []; foreach (var (id, _) in this.iconIdsTask!.Result) { if (this.startRange <= id && id < this.stopRange) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs index d4afce48d..4327fa12f 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs @@ -19,11 +19,11 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class ImGuiWidget : IDataWindowWidget { - private readonly HashSet notifications = new(); + private readonly HashSet notifications = []; private NotificationTemplate notificationTemplate; /// - public string[]? CommandShortcuts { get; init; } = { "imgui" }; + public string[]? CommandShortcuts { get; init; } = ["imgui"]; /// public string DisplayName { get; init; } = "ImGui"; @@ -334,7 +334,7 @@ internal class ImGuiWidget : IDataWindowWidget private struct NotificationTemplate { public static readonly string[] IconTitles = - { + [ "None (use Type)", "SeIconChar", "FontAwesomeIcon", @@ -344,7 +344,7 @@ internal class ImGuiWidget : IDataWindowWidget "TextureWrap from DalamudAssets(Async)", "TextureWrap from GamePath", "TextureWrap from FilePath", - }; + ]; public static readonly string[] AssetSources = Enum.GetValues() @@ -353,46 +353,46 @@ internal class ImGuiWidget : IDataWindowWidget .ToArray(); public static readonly string[] ProgressModeTitles = - { + [ "Default", "Random", "Increasing", "Increasing & Auto Dismiss", "Indeterminate", - }; + ]; public static readonly string[] TypeTitles = - { + [ nameof(NotificationType.None), nameof(NotificationType.Success), nameof(NotificationType.Warning), nameof(NotificationType.Error), nameof(NotificationType.Info), - }; + ]; public static readonly string[] InitialDurationTitles = - { + [ "Infinite", "1 seconds", "3 seconds (default)", "10 seconds", - }; + ]; public static readonly string[] HoverExtendDurationTitles = - { + [ "Disable", "1 seconds", "3 seconds (default)", "10 seconds", - }; + ]; public static readonly TimeSpan[] Durations = - { + [ TimeSpan.Zero, TimeSpan.FromSeconds(1), NotificationConstants.DefaultDuration, TimeSpan.FromSeconds(10), - }; + ]; public bool ManualContent; public string Content; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs index c0ec3d490..f5b26c04c 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs @@ -10,7 +10,9 @@ using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Client.Game; + using Lumina.Excel.Sheets; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/KeyStateWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/KeyStateWidget.cs index fa615ed47..1b45b58fe 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/KeyStateWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/KeyStateWidget.cs @@ -1,4 +1,4 @@ -using Dalamud.Bindings.ImGui; +using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Keys; using Dalamud.Interface.Colors; @@ -10,7 +10,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class KeyStateWidget : IDataWindowWidget { /// - public string[]? CommandShortcuts { get; init; } = { "keystate" }; + public string[]? CommandShortcuts { get; init; } = ["keystate"]; /// public string DisplayName { get; init; } = "KeyState"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/MarketBoardWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/MarketBoardWidget.cs index 56de19de7..382c42f91 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/MarketBoardWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/MarketBoardWidget.cs @@ -1,10 +1,9 @@ -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Globalization; using Dalamud.Bindings.ImGui; using Dalamud.Game.MarketBoard; using Dalamud.Game.Network.Structures; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using ImGuiTable = Dalamud.Interface.Utility.ImGuiTable; @@ -44,7 +43,7 @@ internal class MarketBoardWidget : IDataWindowWidget } /// - public string[]? CommandShortcuts { get; init; } = { "marketboard" }; + public string[]? CommandShortcuts { get; init; } = ["marketboard"]; /// public string DisplayName { get; init; } = "Market Board"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs index 4a32a16df..7761a18b4 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs @@ -42,7 +42,7 @@ internal class NetworkMonitorWidget : IDataWindowWidget } /// - public string[]? CommandShortcuts { get; init; } = { "network", "netmon", "networkmonitor" }; + public string[]? CommandShortcuts { get; init; } = ["network", "netmon", "networkmonitor"]; /// public string DisplayName { get; init; } = "Network Monitor"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/NounProcessorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/NounProcessorWidget.cs index cbf5c3355..eac8b5a52 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/NounProcessorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/NounProcessorWidget.cs @@ -8,6 +8,7 @@ using Dalamud.Game.ClientState; using Dalamud.Game.Text.Noun; using Dalamud.Game.Text.Noun.Enums; using Dalamud.Interface.Utility.Raii; + using Lumina.Data; using Lumina.Excel; using Lumina.Excel.Sheets; @@ -60,7 +61,7 @@ internal class NounProcessorWidget : IDataWindowWidget private int amount = 1; /// - public string[]? CommandShortcuts { get; init; } = { "noun" }; + public string[]? CommandShortcuts { get; init; } = ["noun"]; /// public string DisplayName { get; init; } = "Noun Processor"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs index 71fb18352..dd5dc7472 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs @@ -19,7 +19,7 @@ internal class ObjectTableWidget : IDataWindowWidget private float maxCharaDrawDistance = 20.0f; /// - public string[]? CommandShortcuts { get; init; } = { "ot", "objecttable" }; + public string[]? CommandShortcuts { get; init; } = ["ot", "objecttable"]; /// public string DisplayName { get; init; } = "Object Table"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/PartyListWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/PartyListWidget.cs index e43b231be..4033e4f41 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/PartyListWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/PartyListWidget.cs @@ -1,4 +1,4 @@ -using Dalamud.Bindings.ImGui; +using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Party; using Dalamud.Utility; @@ -12,7 +12,7 @@ internal class PartyListWidget : IDataWindowWidget private bool resolveGameData; /// - public string[]? CommandShortcuts { get; init; } = { "partylist", "party" }; + public string[]? CommandShortcuts { get; init; } = ["partylist", "party"]; /// public string DisplayName { get; init; } = "Party List"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/PluginIpcWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/PluginIpcWidget.cs index 1f1f82cdd..72a02b219 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/PluginIpcWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/PluginIpcWidget.cs @@ -25,7 +25,7 @@ internal class PluginIpcWidget : IDataWindowWidget private string callGateResponse = string.Empty; /// - public string[]? CommandShortcuts { get; init; } = { "ipc" }; + public string[]? CommandShortcuts { get; init; } = ["ipc"]; /// public string DisplayName { get; init; } = "Plugin IPC"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs index 17b7959f6..87c0afe58 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using Dalamud.Bindings.ImGui; using Dalamud.Game.Text; @@ -11,7 +11,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class SeFontTestWidget : IDataWindowWidget { /// - public string[]? CommandShortcuts { get; init; } = { "sefont", "sefonttest" }; + public string[]? CommandShortcuts { get; init; } = ["sefont", "sefonttest"]; /// public string DisplayName { get; init; } = "SeFont Test"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs index 6a07152e5..8f5fe7b8a 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs @@ -13,7 +13,9 @@ using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Internal; using Dalamud.Storage.Assets; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Component.GUI; + using Lumina.Excel.Sheets; using Lumina.Text; using Lumina.Text.Parse; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ServicesWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ServicesWidget.cs index 78ea6d233..3ddc2a888 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ServicesWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ServicesWidget.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Reflection; @@ -16,15 +16,15 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class ServicesWidget : IDataWindowWidget { - private readonly Dictionary nodeRects = new(); - private readonly HashSet selectedNodes = new(); - private readonly HashSet tempRelatedNodes = new(); + private readonly Dictionary nodeRects = []; + private readonly HashSet selectedNodes = []; + private readonly HashSet tempRelatedNodes = []; private bool includeUnloadDependencies; private List>? dependencyNodes; /// - public string[]? CommandShortcuts { get; init; } = { "services" }; + public string[]? CommandShortcuts { get; init; } = ["services"]; /// public string DisplayName { get; init; } = "Service Container"; @@ -280,9 +280,9 @@ internal class ServicesWidget : IDataWindowWidget private class ServiceDependencyNode { - private readonly List parents = new(); - private readonly List children = new(); - private readonly List invalidParents = new(); + private readonly List parents = []; + private readonly List children = []; + private readonly List invalidParents = []; private ServiceDependencyNode(Type t) { @@ -370,7 +370,7 @@ internal class ServicesWidget : IDataWindowWidget foreach (var n in CreateTree(includeUnloadDependencies)) { while (res.Count <= n.Level) - res.Add(new()); + res.Add([]); res[n.Level].Add(n); } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/StartInfoWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/StartInfoWidget.cs index 7fb2cc2bf..c0c38da24 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/StartInfoWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/StartInfoWidget.cs @@ -1,4 +1,5 @@ -using Dalamud.Bindings.ImGui; +using Dalamud.Bindings.ImGui; + using Newtonsoft.Json; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -9,7 +10,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class StartInfoWidget : IDataWindowWidget { /// - public string[]? CommandShortcuts { get; init; } = { "startinfo" }; + public string[]? CommandShortcuts { get; init; } = ["startinfo"]; /// public string DisplayName { get; init; } = "Start Info"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/TargetWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/TargetWidget.cs index 6caf3286d..2e52d7586 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/TargetWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/TargetWidget.cs @@ -14,7 +14,7 @@ internal class TargetWidget : IDataWindowWidget private bool resolveGameData; /// - public string[]? CommandShortcuts { get; init; } = { "target" }; + public string[]? CommandShortcuts { get; init; } = ["target"]; /// public string DisplayName { get; init; } = "Target"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/TaskSchedulerWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/TaskSchedulerWidget.cs index cd72d751e..d9cf0fea2 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/TaskSchedulerWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/TaskSchedulerWidget.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Net.Http; using System.Reflection; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -17,6 +16,7 @@ using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Logging.Internal; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -35,7 +35,7 @@ internal class TaskSchedulerWidget : IDataWindowWidget private CancellationTokenSource taskSchedulerCancelSource = new(); /// - public string[]? CommandShortcuts { get; init; } = { "tasksched", "taskscheduler" }; + public string[]? CommandShortcuts { get; init; } = ["tasksched", "taskscheduler"]; /// public string DisplayName { get; init; } = "Task Scheduler"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs index 3416a2506..e6a092b6e 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/TexWidget.cs @@ -17,6 +17,7 @@ using Dalamud.Interface.Utility.Internal; using Dalamud.Plugin.Services; using Dalamud.Storage.Assets; using Dalamud.Utility; + using TerraFX.Interop.DirectX; using TextureManager = Dalamud.Interface.Textures.Internal.TextureManager; @@ -43,7 +44,7 @@ internal class TexWidget : IDataWindowWidget [DrawBlameTableColumnUserId.NativeAddress] = static x => x.ResourceAddress, }; - private readonly List addedTextures = new(); + private readonly List addedTextures = []; private string allLoadedTexturesTableName = "##table"; private string iconId = "18"; @@ -83,7 +84,7 @@ internal class TexWidget : IDataWindowWidget } /// - public string[]? CommandShortcuts { get; init; } = { "tex", "texture" }; + public string[]? CommandShortcuts { get; init; } = ["tex", "texture"]; /// public string DisplayName { get; init; } = "Tex"; @@ -137,9 +138,9 @@ internal class TexWidget : IDataWindowWidget conf.QueueSave(); } - var allBlames = this.textureManager.BlameTracker; - lock (allBlames) + lock (this.textureManager.BlameTracker) { + var allBlames = this.textureManager.BlameTracker; ImGui.PushID("blames"u8); var sizeSum = allBlames.Sum(static x => Math.Max(0, x.RawSpecs.EstimatedBytes)); if (ImGui.CollapsingHeader( @@ -609,7 +610,7 @@ internal class TexWidget : IDataWindowWidget ImGui.SameLine(); if (ImGuiComponents.IconButton(FontAwesomeIcon.Sync)) - this.textureManager.InvalidatePaths(new[] { texture.SourcePathForDebug }); + this.textureManager.InvalidatePaths([texture.SourcePathForDebug]); if (ImGui.IsItemHovered()) ImGui.SetTooltip($"Call {nameof(ITextureSubstitutionProvider.InvalidatePaths)}."); diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ToastWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ToastWidget.cs index 5e5a077c3..6be0a3a85 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ToastWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ToastWidget.cs @@ -20,7 +20,7 @@ internal class ToastWidget : IDataWindowWidget private bool questToastCheckmark; /// - public string[]? CommandShortcuts { get; init; } = { "toast" }; + public string[]? CommandShortcuts { get; init; } = ["toast"]; /// public string DisplayName { get; init; } = "Toast"; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs index fd3f1d11c..029dc0b75 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs @@ -7,6 +7,7 @@ using Dalamud.Data; using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiSeStringRenderer.Internal; + using Lumina.Excel.Sheets; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs index 7c8110301..cc291af1a 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs @@ -13,6 +13,7 @@ using Dalamud.Interface.Components; using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Utility; using Dalamud.Memory; + using Lumina.Data.Files; using Lumina.Data.Parsing.Uld; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs index f044b2989..d01bd7d78 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs @@ -4,6 +4,7 @@ using System.IO; using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Storage; + using Serilog; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -17,7 +18,7 @@ internal class VfsWidget : IDataWindowWidget private int reps = 1; /// - public string[]? CommandShortcuts { get; init; } = { "vfs" }; + public string[]? CommandShortcuts { get; init; } = ["vfs"]; /// public string DisplayName { get; init; } = "VFS Performance"; diff --git a/Dalamud/Interface/Internal/Windows/GamepadModeNotifierWindow.cs b/Dalamud/Interface/Internal/Windows/GamepadModeNotifierWindow.cs index 91f7f02d9..edad04951 100644 --- a/Dalamud/Interface/Internal/Windows/GamepadModeNotifierWindow.cs +++ b/Dalamud/Interface/Internal/Windows/GamepadModeNotifierWindow.cs @@ -1,6 +1,7 @@ using System.Numerics; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; using Dalamud.Interface.Windowing; diff --git a/Dalamud/Interface/Internal/Windows/PluginImageCache.cs b/Dalamud/Interface/Internal/Windows/PluginImageCache.cs index e95d2e1b8..fb77cf1cf 100644 --- a/Dalamud/Interface/Internal/Windows/PluginImageCache.cs +++ b/Dalamud/Interface/Internal/Windows/PluginImageCache.cs @@ -6,7 +6,6 @@ using System.Net; using System.Threading; using System.Threading.Tasks; -using Dalamud.Game; using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Networking.Http; @@ -15,6 +14,7 @@ using Dalamud.Plugin.Internal.Types; using Dalamud.Plugin.Internal.Types.Manifest; using Dalamud.Storage.Assets; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.Internal.Windows; @@ -51,8 +51,8 @@ internal class PluginImageCache : IInternalDisposableService [ServiceManager.ServiceDependency] private readonly HappyHttpClient happyHttpClient = Service.Get(); - private readonly BlockingCollection>> downloadQueue = new(); - private readonly BlockingCollection> loadQueue = new(); + private readonly BlockingCollection>> downloadQueue = []; + private readonly BlockingCollection> loadQueue = []; private readonly CancellationTokenSource cancelToken = new(); private readonly Task downloadTask; private readonly Task loadTask; @@ -144,7 +144,7 @@ internal class PluginImageCache : IInternalDisposableService this.downloadQueue.CompleteAdding(); this.loadQueue.CompleteAdding(); - if (!Task.WaitAll(new[] { this.loadTask, this.downloadTask }, 4000)) + if (!Task.WaitAll([this.loadTask, this.downloadTask], 4000)) { Log.Error("Plugin Image download/load thread has not cancelled in time"); } @@ -357,7 +357,7 @@ internal class PluginImageCache : IInternalDisposableService try { token.ThrowIfCancellationRequested(); - if (!pendingFuncs.Any()) + if (pendingFuncs.Count == 0) { if (!this.downloadQueue.TryTake(out var taskTuple, -1, token)) return; @@ -373,7 +373,7 @@ internal class PluginImageCache : IInternalDisposableService pendingFuncs = pendingFuncs.OrderBy(x => x.Item1).ToList(); var item1 = pendingFuncs.Last().Item1; - while (pendingFuncs.Any() && pendingFuncs.Last().Item1 == item1) + while (pendingFuncs.Count != 0 && pendingFuncs.Last().Item1 == item1) { token.ThrowIfCancellationRequested(); while (runningTasks.Count >= concurrency) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs index f6171e192..bbc92efb5 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Net.Http.Json; using System.Threading.Tasks; @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Dalamud.Networking.Http; using Dalamud.Plugin.Internal; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.Internal.Windows.PluginInstaller; diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs index 879034fd4..3f964b4b8 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs @@ -1,5 +1,7 @@ -using CheapLoc; +using CheapLoc; + using Dalamud.Plugin.Internal.Types; + using Serilog; namespace Dalamud.Interface.Internal.Windows.PluginInstaller; diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index 3241015fc..e32d31181 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Console; @@ -41,7 +42,7 @@ namespace Dalamud.Interface.Internal.Windows.PluginInstaller; /// internal class PluginInstallerWindow : Window, IDisposable { - private static readonly ModuleLog Log = new("PLUGINW"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly Vector4 changelogBgColor = new(0.114f, 0.584f, 0.192f, 0.678f); private readonly Vector4 changelogTextColor = new(0.812f, 1.000f, 0.816f, 1.000f); @@ -49,7 +50,7 @@ internal class PluginInstallerWindow : Window, IDisposable private readonly PluginImageCache imageCache; private readonly PluginCategoryManager categoryManager = new(); - private readonly List openPluginCollapsibles = new(); + private readonly List openPluginCollapsibles = []; private readonly DateTime timeLoaded; @@ -113,9 +114,9 @@ internal class PluginInstallerWindow : Window, IDisposable private List? updatedPlugins; [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:Elements should appear in the correct order", Justification = "Makes sense like this")] - private List pluginListAvailable = new(); - private List pluginListInstalled = new(); - private List pluginListUpdatable = new(); + private List pluginListAvailable = []; + private List pluginListInstalled = []; + private List pluginListUpdatable = []; private bool hasDevPlugins = false; private bool hasHiddenPlugins = false; @@ -2360,7 +2361,7 @@ internal class PluginInstallerWindow : Window, IDisposable else if (!string.IsNullOrWhiteSpace(manifest.Description)) { const int punchlineLen = 200; - var firstLine = manifest.Description.Split(new[] { '\r', '\n' })[0]; + var firstLine = manifest.Description.Split(['\r', '\n'])[0]; ImGui.TextWrapped(firstLine.Length < punchlineLen ? firstLine diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs index fb2719868..c01d7f390 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/ProfileManagerWidget.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Threading.Tasks; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Interface.Colors; @@ -15,6 +16,7 @@ using Dalamud.Interface.Utility.Raii; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal.Profiles; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.Internal.Windows.PluginInstaller; @@ -403,7 +405,7 @@ internal class ProfileManagerWidget ImGui.Text(Locs.StartupBehavior); if (ImGui.BeginCombo("##startupBehaviorPicker"u8, Locs.PolicyToLocalisedName(profile.StartupPolicy))) { - foreach (var policy in Enum.GetValues(typeof(ProfileModelV1.ProfileStartupPolicy)).Cast()) + foreach (var policy in Enum.GetValues()) { var name = Locs.PolicyToLocalisedName(policy); if (ImGui.Selectable(name, profile.StartupPolicy == policy)) diff --git a/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs b/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs index b8e10020e..8b702123c 100644 --- a/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginStatWindow.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Reflection; @@ -14,6 +13,7 @@ using Dalamud.Interface.Windowing; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal.Types; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.Internal.Windows; @@ -186,7 +186,7 @@ internal class PluginStatWindow : Window ImGui.SameLine(); ImGuiComponents.TextWithLabel("Total Average", $"{totalAverage:F4}ms", "All average update times added together"); ImGui.SameLine(); - ImGuiComponents.TextWithLabel("Collective Average", $"{(statsHistory.Any() ? totalAverage / statsHistory.Length : 0):F4}ms", "Average of all average update times"); + ImGuiComponents.TextWithLabel("Collective Average", $"{(statsHistory.Length != 0 ? totalAverage / statsHistory.Length : 0):F4}ms", "Average of all average update times"); ImGui.InputTextWithHint( "###PluginStatWindow_FrameworkSearch"u8, @@ -230,7 +230,7 @@ internal class PluginStatWindow : Window foreach (var handlerHistory in statsHistory) { - if (!handlerHistory.Value.Any()) + if (handlerHistory.Value.Count == 0) { continue; } diff --git a/Dalamud/Interface/Internal/Windows/ProfilerWindow.cs b/Dalamud/Interface/Internal/Windows/ProfilerWindow.cs index abe8d1584..8ff407cd7 100644 --- a/Dalamud/Interface/Internal/Windows/ProfilerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/ProfilerWindow.cs @@ -19,7 +19,7 @@ public class ProfilerWindow : Window { private double min; private double max; - private List>> occupied = new(); + private List>> occupied = []; /// /// Initializes a new instance of the class. @@ -109,7 +109,7 @@ public class ProfilerWindow : Window } if (depth == this.occupied.Count) - this.occupied.Add(new()); + this.occupied.Add([]); this.occupied[depth].Add(Tuple.Create(timingHandle.StartTime, timingHandle.EndTime)); parentDepthDict[timingHandle.Id] = depth; @@ -188,7 +188,7 @@ public class ProfilerWindow : Window } } - uint eventTextDepth = maxRectDept + 2; + var eventTextDepth = maxRectDept + 2; var eventsXPos = new List(); const float eventsXPosFudge = 5f; diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs b/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs index ea8cd0070..0335cafc5 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/SelfTestWindow.cs @@ -10,6 +10,7 @@ using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using Dalamud.Logging.Internal; + using Dalamud.Plugin.SelfTest; using Dalamud.Plugin.SelfTest.Internal; using Dalamud.Utility; @@ -21,11 +22,11 @@ namespace Dalamud.Interface.Internal.Windows.SelfTest; /// internal class SelfTestWindow : Window { - private static readonly ModuleLog Log = new("AGING"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly SelfTestRegistry selfTestRegistry; - private List visibleSteps = new(); + private List visibleSteps = []; private bool selfTestRunning = false; private SelfTestGroup? currentTestGroup = null; @@ -138,7 +139,7 @@ internal class SelfTestWindow : Window ImGui.SameLine(); var stepNumber = this.currentStep != null ? this.visibleSteps.IndexOf(this.currentStep) : 0; - ImGui.Text($"Step: {stepNumber} / {this.visibleSteps.Count}"); + ImGui.Text($"Step: {stepNumber} / {this.visibleSteps.Count}"); ImGui.Spacing(); diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/AddonLifecycleSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/AddonLifecycleSelfTestStep.cs index d9c9facc7..e2c1a40df 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/AddonLifecycleSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/AddonLifecycleSelfTestStep.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Dalamud.Bindings.ImGui; using Dalamud.Game.Addon.Lifecycle; @@ -23,15 +23,15 @@ internal class AddonLifecycleSelfTestStep : ISelfTestStep /// public AddonLifecycleSelfTestStep() { - this.listeners = new List - { + this.listeners = + [ new(AddonEvent.PostSetup, "Character", this.PostSetup), new(AddonEvent.PostUpdate, "Character", this.PostUpdate), new(AddonEvent.PostDraw, "Character", this.PostDraw), new(AddonEvent.PostRefresh, "Character", this.PostRefresh), new(AddonEvent.PostRequestedUpdate, "Character", this.PostRequestedUpdate), new(AddonEvent.PreFinalize, "Character", this.PreFinalize), - }; + ]; } private enum TestStep diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/CompletionSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/CompletionSelfTestStep.cs index a34b058bd..1f33e5dd2 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/CompletionSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/CompletionSelfTestStep.cs @@ -1,6 +1,5 @@ using Dalamud.Bindings.ImGui; using Dalamud.Game.Command; -using Dalamud.Interface.Utility; using Dalamud.Plugin.SelfTest; namespace Dalamud.Interface.Internal.Windows.SelfTest.Steps; diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ConditionSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ConditionSelfTestStep.cs index 89083da48..1c9b589d0 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ConditionSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ConditionSelfTestStep.cs @@ -1,6 +1,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Conditions; using Dalamud.Plugin.SelfTest; + using Serilog; namespace Dalamud.Interface.Internal.Windows.SelfTest.Steps; diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ContextMenuSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ContextMenuSelfTestStep.cs index 0fe5b4443..b61c62589 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ContextMenuSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/ContextMenuSelfTestStep.cs @@ -9,8 +9,10 @@ using Dalamud.Game.Gui.ContextMenu; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.SelfTest; + using Lumina.Excel; using Lumina.Excel.Sheets; + using Serilog; namespace Dalamud.Interface.Internal.Windows.SelfTest.Steps; diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/FrameworkTaskSchedulerSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/FrameworkTaskSchedulerSelfTestStep.cs index eb6909fa7..c5f3ab76b 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/FrameworkTaskSchedulerSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/FrameworkTaskSchedulerSelfTestStep.cs @@ -4,8 +4,6 @@ using Dalamud.Game; using Dalamud.Plugin.SelfTest; using Dalamud.Utility; -using Microsoft.VisualBasic.Logging; - using Log = Serilog.Log; namespace Dalamud.Interface.Internal.Windows.SelfTest.Steps; diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/LuminaSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/LuminaSelfTestStep.cs index 741dd71b1..dd8a16689 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/LuminaSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/LuminaSelfTestStep.cs @@ -1,6 +1,7 @@ using Dalamud.Data; using Dalamud.Plugin.SelfTest; using Dalamud.Utility; + using Lumina.Excel; namespace Dalamud.Interface.Internal.Windows.SelfTest.Steps; diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/MarketBoardSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/MarketBoardSelfTestStep.cs index 6a45f343a..ff6b64383 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/MarketBoardSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/MarketBoardSelfTestStep.cs @@ -4,7 +4,6 @@ using System.Linq; using Dalamud.Bindings.ImGui; using Dalamud.Game.MarketBoard; using Dalamud.Game.Network.Structures; -using Dalamud.Interface.Utility; using Dalamud.Plugin.SelfTest; namespace Dalamud.Interface.Internal.Windows.SelfTest.Steps; diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/NamePlateSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/NamePlateSelfTestStep.cs index 9cc6045a6..7136c8801 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/NamePlateSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/NamePlateSelfTestStep.cs @@ -36,7 +36,7 @@ internal class NamePlateSelfTestStep : ISelfTestStep namePlateGui.OnNamePlateUpdate += this.OnNamePlateUpdate; namePlateGui.OnDataUpdate += this.OnDataUpdate; namePlateGui.RequestRedraw(); - this.updateCount = new Dictionary(); + this.updateCount = []; this.currentSubStep++; break; diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/SheetRedirectResolverSelfTestStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/SheetRedirectResolverSelfTestStep.cs index c285fda46..c99ec91de 100644 --- a/Dalamud/Interface/Internal/Windows/SelfTest/Steps/SheetRedirectResolverSelfTestStep.cs +++ b/Dalamud/Interface/Internal/Windows/SelfTest/Steps/SheetRedirectResolverSelfTestStep.cs @@ -4,6 +4,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Game; using Dalamud.Game.Text.Evaluator.Internal; using Dalamud.Plugin.SelfTest; + using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI.Misc; diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs index 62c931b20..aa8d1dc3a 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Numerics; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Interface.Colors; diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs index 4785ceb3c..1d5eebb85 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Numerics; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Game.Gui; using Dalamud.Interface.GameFonts; @@ -15,6 +16,7 @@ using Dalamud.Interface.Utility.Raii; using Dalamud.Plugin.Internal; using Dalamud.Storage.Assets; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Client.Game.UI; namespace Dalamud.Interface.Internal.Windows.Settings.Tabs; diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAutoUpdate.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAutoUpdate.cs index 6b99c5c24..b03a0f51c 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAutoUpdate.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAutoUpdate.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Numerics; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Interface.Colors; diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs index 4b055b35b..18382b1f8 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Numerics; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Game.Gui.Dtr; diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs index 9b2c418b6..f2ca1f53a 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Text; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Game; diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/EnumSettingsEntry{T}.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/EnumSettingsEntry{T}.cs index 8fb91940e..096e408b8 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Widgets/EnumSettingsEntry{T}.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/EnumSettingsEntry{T}.cs @@ -2,8 +2,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; -using CheapLoc; - using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Interface.Colors; diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs index 5737b44db..daa91420f 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs @@ -5,6 +5,7 @@ using System.Numerics; using System.Threading.Tasks; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration; using Dalamud.Configuration.Internal; diff --git a/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs index f9e8022a1..4add874ba 100644 --- a/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs +++ b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Reflection; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Interface.Colors; @@ -12,6 +12,7 @@ using Dalamud.Interface.Style; using Dalamud.Interface.Utility; using Dalamud.Interface.Windowing; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.Internal.Windows.StyleEditor; @@ -50,7 +51,7 @@ public class StyleEditorWindow : Window this.didSave = false; var config = Service.Get(); - config.SavedStyles ??= new List(); + config.SavedStyles ??= []; this.currentSel = config.SavedStyles.FindIndex(x => x.Name == config.ChosenStyle); this.initialStyle = config.ChosenStyle; diff --git a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs index ec9440e0e..9d4f7ab04 100644 --- a/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs +++ b/Dalamud/Interface/Internal/Windows/TitleScreenMenuWindow.cs @@ -22,8 +22,11 @@ using Dalamud.Plugin.Internal; using Dalamud.Plugin.Services; using Dalamud.Storage.Assets; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Component.GUI; + using Lumina.Text.ReadOnly; + using Serilog; namespace Dalamud.Interface.Internal.Windows; @@ -47,9 +50,9 @@ internal class TitleScreenMenuWindow : Window, IDisposable private readonly Lazy shadeTexture; private readonly AddonLifecycleEventListener versionStringListener; - private readonly Dictionary shadeEasings = new(); - private readonly Dictionary moveEasings = new(); - private readonly Dictionary logoEasings = new(); + private readonly Dictionary shadeEasings = []; + private readonly Dictionary moveEasings = []; + private readonly Dictionary logoEasings = []; private readonly IConsoleVariable showTsm; diff --git a/Dalamud/Interface/ManagedFontAtlas/FontAtlasBuildToolkitUtilities.cs b/Dalamud/Interface/ManagedFontAtlas/FontAtlasBuildToolkitUtilities.cs index 2e497b6cd..b2b2c2ab1 100644 --- a/Dalamud/Interface/ManagedFontAtlas/FontAtlasBuildToolkitUtilities.cs +++ b/Dalamud/Interface/ManagedFontAtlas/FontAtlasBuildToolkitUtilities.cs @@ -3,7 +3,6 @@ using System.Runtime.CompilerServices; using System.Text.Unicode; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Utility; namespace Dalamud.Interface.ManagedFontAtlas; diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/DelegateFontHandle.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/DelegateFontHandle.cs index f2c91d264..0e2f503b4 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/DelegateFontHandle.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/DelegateFontHandle.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Threading; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Utility; @@ -34,8 +35,8 @@ internal sealed class DelegateFontHandle : FontHandle /// internal sealed class HandleManager : IFontHandleManager { - private readonly HashSet handles = new(); - private readonly object syncRoot = new(); + private readonly HashSet handles = []; + private readonly Lock syncRoot = new(); /// /// Initializes a new instance of the class. @@ -95,8 +96,8 @@ internal sealed class DelegateFontHandle : FontHandle private static readonly ModuleLog Log = new($"{nameof(DelegateFontHandle)}.{nameof(HandleSubstance)}"); // Owned by this class, but ImFontPtr values still do not belong to this. - private readonly Dictionary fonts = new(); - private readonly Dictionary buildExceptions = new(); + private readonly Dictionary fonts = []; + private readonly Dictionary buildExceptions = []; /// /// Initializes a new instance of the class. diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.BuildToolkit.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.BuildToolkit.cs index 41c87fd39..97dc29804 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.BuildToolkit.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.BuildToolkit.cs @@ -15,6 +15,7 @@ using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Storage.Assets; using Dalamud.Utility; + using TerraFX.Interop.DirectX; namespace Dalamud.Interface.ManagedFontAtlas.Internals; @@ -24,8 +25,7 @@ namespace Dalamud.Interface.ManagedFontAtlas.Internals; /// internal sealed partial class FontAtlasFactory { - private static readonly Dictionary> PairAdjustmentsCache = - new(); + private static readonly Dictionary> PairAdjustmentsCache = []; /// /// Implementations for and @@ -43,7 +43,7 @@ internal sealed partial class FontAtlasFactory private readonly GamePrebakedFontHandle.HandleSubstance gameFontHandleSubstance; private readonly FontAtlasFactory factory; private readonly FontAtlasBuiltData data; - private readonly List registeredPostBuildActions = new(); + private readonly List registeredPostBuildActions = []; /// /// Initializes a new instance of the class. @@ -85,7 +85,7 @@ internal sealed partial class FontAtlasFactory /// /// Gets the font scale modes. /// - private Dictionary FontScaleModes { get; } = new(); + private Dictionary FontScaleModes { get; } = []; /// public void Dispose() => this.disposeAfterBuild.Dispose(); @@ -170,7 +170,7 @@ internal sealed partial class FontAtlasFactory }; if (fontConfig.GlyphRanges is not { Length: > 0 } ranges) - ranges = new ushort[] { 1, 0xFFFE, 0 }; + ranges = [1, 0xFFFE, 0]; raw.GlyphRanges = (ushort*)this.DisposeAfterBuild( GCHandle.Alloc(ranges, GCHandleType.Pinned)).AddrOfPinnedObject(); @@ -188,7 +188,7 @@ internal sealed partial class FontAtlasFactory { if (!PairAdjustmentsCache.TryGetValue(hashIdent, out pairAdjustments)) { - PairAdjustmentsCache.Add(hashIdent, pairAdjustments = new()); + PairAdjustmentsCache.Add(hashIdent, pairAdjustments = []); try { pairAdjustments.AddRange(TrueTypeUtils.ExtractHorizontalPairAdjustments(raw).ToArray()); @@ -382,7 +382,7 @@ internal sealed partial class FontAtlasFactory DalamudAsset.FontAwesomeFreeSolid, fontConfig with { - GlyphRanges = new ushort[] { FontAwesomeIconMin, FontAwesomeIconMax, 0 }, + GlyphRanges = [FontAwesomeIconMin, FontAwesomeIconMax, 0], }); /// @@ -391,12 +391,12 @@ internal sealed partial class FontAtlasFactory DalamudAsset.LodestoneGameSymbol, fontConfig with { - GlyphRanges = new ushort[] - { + GlyphRanges = + [ GamePrebakedFontHandle.SeIconCharMin, GamePrebakedFontHandle.SeIconCharMax, 0, - }, + ], }); /// @@ -629,7 +629,7 @@ internal sealed partial class FontAtlasFactory { this.AddDalamudAssetFont( DalamudAsset.NotoSansJpMedium, - new() { GlyphRanges = new ushort[] { ' ', ' ', '\0' }, SizePx = 1 }); + new() { GlyphRanges = [' ', ' ', '\0'], SizePx = 1 }); } if (!this.NewImAtlas.Build()) diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs index 430f26127..323d4173d 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.Implementation.cs @@ -1,4 +1,4 @@ -// #define VeryVerboseLog +// #define VeryVerboseLog using System.Collections.Generic; using System.Diagnostics; @@ -41,9 +41,9 @@ internal sealed partial class FontAtlasFactory /// /// If set, disables concurrent font build operation. /// - private static readonly object? NoConcurrentBuildOperationLock = null; // new(); + private static readonly Lock? NoConcurrentBuildOperationLock = null; // new(); - private static readonly ModuleLog Log = new(nameof(FontAtlasFactory)); + private static readonly ModuleLog Log = ModuleLog.Create(); private static readonly Task EmptyTask = Task.FromResult(default(FontAtlasBuiltData)); @@ -66,10 +66,10 @@ internal sealed partial class FontAtlasFactory try { - var substancesList = this.substances = new(); + var substancesList = this.substances = []; this.Garbage.Add(() => substancesList.Clear()); - var wrapsCopy = this.wraps = new(); + var wrapsCopy = this.wraps = []; this.Garbage.Add(() => wrapsCopy.Clear()); var atlasPtr = ImGui.ImFontAtlas(); @@ -115,16 +115,14 @@ internal sealed partial class FontAtlasFactory public void AddExistingTexture(IDalamudTextureWrap wrap) { - if (this.wraps is null) - throw new ObjectDisposedException(nameof(FontAtlasBuiltData)); + ObjectDisposedException.ThrowIf(this.wraps == null, this); this.wraps.Add(this.Garbage.Add(wrap)); } public int AddNewTexture(IDalamudTextureWrap wrap, bool disposeOnError) { - if (this.wraps is null) - throw new ObjectDisposedException(nameof(FontAtlasBuiltData)); + ObjectDisposedException.ThrowIf(this.wraps == null, this); var handle = wrap.Handle; var index = this.ImTextures.IndexOf(x => x.TexID == handle); @@ -254,7 +252,7 @@ internal sealed partial class FontAtlasFactory private readonly GamePrebakedFontHandle.HandleManager gameFontHandleManager; private readonly IFontHandleManager[] fontHandleManagers; - private readonly object syncRoot = new(); + private readonly Lock syncRoot = new(); private Task buildTask = EmptyTask; private FontAtlasBuiltData? builtData; @@ -292,13 +290,13 @@ internal sealed partial class FontAtlasFactory this.factory.InterfaceManager.AfterBuildFonts += this.OnRebuildRecommend; this.disposables.Add(() => this.factory.InterfaceManager.AfterBuildFonts -= this.OnRebuildRecommend); - this.fontHandleManagers = new IFontHandleManager[] - { + this.fontHandleManagers = + [ this.delegateFontHandleManager = this.disposables.Add( new DelegateFontHandle.HandleManager(atlasName)), this.gameFontHandleManager = this.disposables.Add( new GamePrebakedFontHandle.HandleManager(atlasName, factory)), - }; + ]; foreach (var fhm in this.fontHandleManagers) fhm.RebuildRecommend += this.OnRebuildRecommend; } diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.cs index 6ae810dec..55c2acdbc 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/FontAtlasFactory.cs @@ -18,7 +18,9 @@ using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Plugin.Internal.Types; using Dalamud.Storage.Assets; using Dalamud.Utility; + using Lumina.Data.Files; + using TerraFX.Interop.DirectX; namespace Dalamud.Interface.ManagedFontAtlas.Internals; diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/FontHandle.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/FontHandle.cs index 98a823deb..ce67b0eec 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/FontHandle.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/FontHandle.cs @@ -10,6 +10,7 @@ using Dalamud.Interface.Utility; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal.Types; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface.ManagedFontAtlas.Internals; @@ -20,7 +21,7 @@ namespace Dalamud.Interface.ManagedFontAtlas.Internals; internal abstract class FontHandle : IFontHandle { private const int NonMainThreadFontAccessWarningCheckInterval = 10000; - private static readonly ConditionalWeakTable NonMainThreadFontAccessWarning = new(); + private static readonly ConditionalWeakTable NonMainThreadFontAccessWarning = []; private static long nextNonMainThreadFontAccessWarningCheck; private readonly List pushedFonts = new(8); diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/GamePrebakedFontHandle.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/GamePrebakedFontHandle.cs index f6904db7c..81c7d4d89 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/GamePrebakedFontHandle.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/GamePrebakedFontHandle.cs @@ -4,14 +4,15 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reactive.Disposables; +using System.Threading; using Dalamud.Bindings.ImGui; using Dalamud.Game.Text; using Dalamud.Interface.GameFonts; -using Dalamud.Interface.Internal; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Utility; + using Lumina.Data.Files; using Vector4 = System.Numerics.Vector4; @@ -101,9 +102,9 @@ internal class GamePrebakedFontHandle : FontHandle /// internal sealed class HandleManager : IFontHandleManager { - private readonly Dictionary gameFontsRc = new(); - private readonly HashSet handles = new(); - private readonly object syncRoot = new(); + private readonly Dictionary gameFontsRc = []; + private readonly HashSet handles = []; + private readonly Lock syncRoot = new(); /// /// Initializes a new instance of the class. @@ -188,11 +189,11 @@ internal class GamePrebakedFontHandle : FontHandle private readonly HashSet gameFontStyles; // Owned by this class, but ImFontPtr values still do not belong to this. - private readonly Dictionary fonts = new(); - private readonly Dictionary buildExceptions = new(); - private readonly List<(ImFontPtr Font, GameFontStyle Style, ushort[]? Ranges)> attachments = new(); + private readonly Dictionary fonts = []; + private readonly Dictionary buildExceptions = []; + private readonly List<(ImFontPtr Font, GameFontStyle Style, ushort[]? Ranges)> attachments = []; - private readonly HashSet templatedFonts = new(); + private readonly HashSet templatedFonts = []; /// /// Initializes a new instance of the class. @@ -415,7 +416,7 @@ internal class GamePrebakedFontHandle : FontHandle DalamudAsset.NotoSansJpMedium, new() { - GlyphRanges = new ushort[] { ' ', ' ', '\0' }, + GlyphRanges = [' ', ' ', '\0'], SizePx = sizePx, }); this.templatedFonts.Add(font); @@ -449,8 +450,8 @@ internal class GamePrebakedFontHandle : FontHandle public readonly GameFontStyle BaseStyle; public readonly GameFontFamilyAndSizeAttribute BaseAttr; public readonly int TexCount; - public readonly Dictionary Ranges = new(); - public readonly List<(int RectId, int FdtGlyphIndex)> Rects = new(); + public readonly Dictionary Ranges = []; + public readonly List<(int RectId, int FdtGlyphIndex)> Rects = []; public readonly ushort[] RectLookup = new ushort[0x10000]; public readonly FdtFileView Fdt; public readonly ImFontPtr FullRangeFont; diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/LockedImFont.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/LockedImFont.cs index b7f5ad12b..9eb90fe16 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/LockedImFont.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/LockedImFont.cs @@ -34,8 +34,7 @@ internal class LockedImFont : ILockedImFont /// public ILockedImFont NewRef() { - if (this.owner is null) - throw new ObjectDisposedException(nameof(LockedImFont)); + ObjectDisposedException.ThrowIf(this.owner == null, this); var newRef = new LockedImFont(this.ImFont, this.owner); this.owner.AddRef(); diff --git a/Dalamud/Interface/ManagedFontAtlas/Internals/SimplePushedFont.cs b/Dalamud/Interface/ManagedFontAtlas/Internals/SimplePushedFont.cs index 0d6ad5c7c..ed40ce28b 100644 --- a/Dalamud/Interface/ManagedFontAtlas/Internals/SimplePushedFont.cs +++ b/Dalamud/Interface/ManagedFontAtlas/Internals/SimplePushedFont.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Diagnostics; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Utility; using Microsoft.Extensions.ObjectPool; diff --git a/Dalamud/Interface/Style/DalamudColors.cs b/Dalamud/Interface/Style/DalamudColors.cs index aa3339c19..e4a8c5b9b 100644 --- a/Dalamud/Interface/Style/DalamudColors.cs +++ b/Dalamud/Interface/Style/DalamudColors.cs @@ -1,6 +1,7 @@ -using System.Numerics; +using System.Numerics; using Dalamud.Interface.Colors; + using Newtonsoft.Json; namespace Dalamud.Interface.Style; diff --git a/Dalamud/Interface/Style/StyleModel.cs b/Dalamud/Interface/Style/StyleModel.cs index bfce480f2..4c64e3a21 100644 --- a/Dalamud/Interface/Style/StyleModel.cs +++ b/Dalamud/Interface/Style/StyleModel.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Numerics; @@ -6,7 +6,9 @@ using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Interface.Colors; using Dalamud.Utility; + using Newtonsoft.Json; + using Serilog; namespace Dalamud.Interface.Style; @@ -68,7 +70,7 @@ public abstract class StyleModel /// Thrown in case the version of the model is not known. public static StyleModel? Deserialize(string model) { - var json = Util.DecompressString(Convert.FromBase64String(model.Substring(3))); + var json = Util.DecompressString(Convert.FromBase64String(model[3..])); if (model.StartsWith(StyleModelV1.SerializedPrefix)) return JsonConvert.DeserializeObject(json); @@ -86,8 +88,7 @@ public abstract class StyleModel if (configuration.SavedStylesOld == null) return; - configuration.SavedStyles = new List(); - configuration.SavedStyles.AddRange(configuration.SavedStylesOld); + configuration.SavedStyles = [.. configuration.SavedStylesOld]; Log.Information("Transferred {NumStyles} styles", configuration.SavedStyles.Count); @@ -102,16 +103,11 @@ public abstract class StyleModel /// Thrown when the version of the style model is unknown. public string Serialize() { - string prefix; - switch (this) + var prefix = this switch { - case StyleModelV1: - prefix = StyleModelV1.SerializedPrefix; - break; - default: - throw new ArgumentOutOfRangeException(); - } - + StyleModelV1 => StyleModelV1.SerializedPrefix, + _ => throw new ArgumentOutOfRangeException(), + }; return prefix + Convert.ToBase64String(Util.CompressString(JsonConvert.SerializeObject(this))); } diff --git a/Dalamud/Interface/Style/StyleModelV1.cs b/Dalamud/Interface/Style/StyleModelV1.cs index 8c1de86f3..4af2512fd 100644 --- a/Dalamud/Interface/Style/StyleModelV1.cs +++ b/Dalamud/Interface/Style/StyleModelV1.cs @@ -3,6 +3,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Colors; + using Newtonsoft.Json; namespace Dalamud.Interface.Style; @@ -17,7 +18,7 @@ public class StyleModelV1 : StyleModel /// private StyleModelV1() { - this.Colors = new Dictionary(); + this.Colors = []; this.Name = "Unknown"; } @@ -396,7 +397,7 @@ public class StyleModelV1 : StyleModel model.SelectableTextAlign = style.SelectableTextAlign; model.DisplaySafeAreaPadding = style.DisplaySafeAreaPadding; - model.Colors = new Dictionary(); + model.Colors = []; foreach (var imGuiCol in Enum.GetValues()) { diff --git a/Dalamud/Interface/Textures/ForwardingSharedImmediateTexture.cs b/Dalamud/Interface/Textures/ForwardingSharedImmediateTexture.cs index 12e312b3e..45dc69bbd 100644 --- a/Dalamud/Interface/Textures/ForwardingSharedImmediateTexture.cs +++ b/Dalamud/Interface/Textures/ForwardingSharedImmediateTexture.cs @@ -1,8 +1,7 @@ -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Dalamud.Interface.Textures.TextureWraps; -using Dalamud.Storage.Assets; namespace Dalamud.Interface.Textures; diff --git a/Dalamud/Interface/Textures/ISharedImmediateTexture.cs b/Dalamud/Interface/Textures/ISharedImmediateTexture.cs index b6aa4da83..7f3b54c97 100644 --- a/Dalamud/Interface/Textures/ISharedImmediateTexture.cs +++ b/Dalamud/Interface/Textures/ISharedImmediateTexture.cs @@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; -using Dalamud.Interface.Internal; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Utility; diff --git a/Dalamud/Interface/Textures/ImGuiViewportTextureArgs.cs b/Dalamud/Interface/Textures/ImGuiViewportTextureArgs.cs index d04688fe4..248fbbc67 100644 --- a/Dalamud/Interface/Textures/ImGuiViewportTextureArgs.cs +++ b/Dalamud/Interface/Textures/ImGuiViewportTextureArgs.cs @@ -2,9 +2,7 @@ using System.Numerics; using System.Text; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Internal; using Dalamud.Interface.Textures.TextureWraps; -using TerraFX.Interop.DirectX; namespace Dalamud.Interface.Textures; diff --git a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/ManifestResourceSharedImmediateTexture.cs b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/ManifestResourceSharedImmediateTexture.cs index c95a9b0ad..511f6e110 100644 --- a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/ManifestResourceSharedImmediateTexture.cs +++ b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/ManifestResourceSharedImmediateTexture.cs @@ -3,7 +3,6 @@ using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Dalamud.Interface.Internal; using Dalamud.Interface.Textures.TextureWraps; namespace Dalamud.Interface.Textures.Internal.SharedImmediateTextures; @@ -36,10 +35,7 @@ internal sealed class ManifestResourceSharedImmediateTexture : SharedImmediateTe /// protected override async Task CreateTextureAsync(CancellationToken cancellationToken) { - await using var stream = this.assembly.GetManifestResourceStream(this.name); - if (stream is null) - throw new FileNotFoundException("The resource file could not be found."); - + await using var stream = this.assembly.GetManifestResourceStream(this.name) ?? throw new FileNotFoundException("The resource file could not be found."); var tm = await Service.GetAsync(); var ms = new MemoryStream(stream.CanSeek ? checked((int)stream.Length) : 0); await stream.CopyToAsync(ms, cancellationToken); diff --git a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs index 5f9925ed3..931a1a73b 100644 --- a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs +++ b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/SharedImmediateTexture.cs @@ -23,8 +23,8 @@ internal abstract class SharedImmediateTexture private static long instanceCounter; - private readonly object reviveLock = new(); - private readonly List ownerPlugins = new(); + private readonly Lock reviveLock = new(); + private readonly List ownerPlugins = []; private bool resourceReleased; private int refCount; @@ -476,8 +476,8 @@ internal abstract class SharedImmediateTexture { var ownerCopy = this.owner; var wrapCopy = this.innerWrap; - if (ownerCopy is null || wrapCopy is null) - throw new ObjectDisposedException(nameof(RefCountableWrappingTextureWrap)); + + ObjectDisposedException.ThrowIf(ownerCopy is null || wrapCopy is null, this); ownerCopy.AddRef(); return new RefCountableWrappingTextureWrap(wrapCopy, ownerCopy); diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs b/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs index fde40d462..ed1824e5c 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.BlameTracker.cs @@ -3,7 +3,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Internal; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Plugin.Internal.Types; using Dalamud.Plugin.Services; @@ -44,7 +43,7 @@ internal sealed partial class TextureManager /// Gets the list containing all the loaded textures from plugins. /// Returned value must be used inside a lock. - public List BlameTracker { get; } = new(); + public List BlameTracker { get; } = []; /// Gets the blame for a texture wrap. /// The texture wrap. @@ -234,7 +233,7 @@ internal sealed partial class TextureManager public static Guid* NativeGuid => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in MyGuid)); /// - public List OwnerPlugins { get; } = new(); + public List OwnerPlugins { get; } = []; /// public nint ResourceAddress => (nint)this.tex2D; diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.Drawer.cs b/Dalamud/Interface/Textures/Internal/TextureManager.Drawer.cs index b4573f04f..e803a1d13 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.Drawer.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.Drawer.cs @@ -5,6 +5,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Storage.Assets; using Dalamud.Utility; + using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.GamePath.cs b/Dalamud/Interface/Textures/Internal/TextureManager.GamePath.cs index 0796ad6cc..fe0f390eb 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.GamePath.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.GamePath.cs @@ -113,8 +113,8 @@ internal sealed partial class TextureManager var format = highResolution ? HighResolutionIconFileFormat : IconFileFormat; type ??= string.Empty; - if (type.Length > 0 && !type.EndsWith("/")) - type += "/"; + if (type.Length > 0 && !type.EndsWith('/')) + type += '/'; return string.Format(format, iconId / 1000, type, iconId); } diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.SharedTextures.cs b/Dalamud/Interface/Textures/Internal/TextureManager.SharedTextures.cs index d7e185b68..85cf3a1ca 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.SharedTextures.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.SharedTextures.cs @@ -5,7 +5,6 @@ using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; -using System.Threading.Tasks; using BitFaster.Caching.Lru; @@ -65,7 +64,7 @@ internal sealed partial class TextureManager private readonly ConcurrentDictionary gameDict = new(); private readonly ConcurrentDictionary fileDict = new(); private readonly ConcurrentDictionary<(Assembly, string), SharedImmediateTexture> manifestResourceDict = new(); - private readonly HashSet invalidatedTextures = new(); + private readonly HashSet invalidatedTextures = []; private readonly Thread sharedTextureReleaseThread; diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.cs b/Dalamud/Interface/Textures/Internal/TextureManager.cs index d0f0d8c07..982b5c58d 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.cs @@ -34,7 +34,7 @@ internal sealed partial class TextureManager ITextureSubstitutionProvider, ITextureReadbackProvider { - private static readonly ModuleLog Log = new(nameof(TextureManager)); + private static readonly ModuleLog Log = ModuleLog.Create(); [ServiceManager.ServiceDependency] private readonly Dalamud dalamud = Service.Get(); @@ -382,10 +382,10 @@ internal sealed partial class TextureManager var tf = new TexFile(); typeof(TexFile).GetProperty(nameof(tf.Data))!.GetSetMethod(true)!.Invoke( tf, - new object?[] { bytesArray }); + [bytesArray]); typeof(TexFile).GetProperty(nameof(tf.Reader))!.GetSetMethod(true)!.Invoke( tf, - new object?[] { new LuminaBinaryReader(bytesArray) }); + [new LuminaBinaryReader(bytesArray)]); // Note: FileInfo and FilePath are not used from TexFile; skip it. var wrap = this.NoThrottleCreateFromTexFile(tf); diff --git a/Dalamud/Interface/Textures/TextureWraps/ForwardingTextureWrap.cs b/Dalamud/Interface/Textures/TextureWraps/ForwardingTextureWrap.cs index 342397c5e..2cb1deac5 100644 --- a/Dalamud/Interface/Textures/TextureWraps/ForwardingTextureWrap.cs +++ b/Dalamud/Interface/Textures/TextureWraps/ForwardingTextureWrap.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Internal; using Dalamud.Interface.Textures.TextureWraps.Internal; using TerraFX.Interop.Windows; diff --git a/Dalamud/Interface/Textures/TextureWraps/Internal/ViewportTextureWrap.cs b/Dalamud/Interface/Textures/TextureWraps/Internal/ViewportTextureWrap.cs index 3e0f31eca..d4407d76a 100644 --- a/Dalamud/Interface/Textures/TextureWraps/Internal/ViewportTextureWrap.cs +++ b/Dalamud/Interface/Textures/TextureWraps/Internal/ViewportTextureWrap.cs @@ -9,6 +9,7 @@ using Dalamud.Interface.Textures.Internal; using Dalamud.Plugin.Internal.Types; using Dalamud.Storage.Assets; using Dalamud.Utility; + using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; diff --git a/Dalamud/Interface/TitleScreenMenu/TitleScreenMenu.cs b/Dalamud/Interface/TitleScreenMenu/TitleScreenMenu.cs index 586d65559..cf849a1ef 100644 --- a/Dalamud/Interface/TitleScreenMenu/TitleScreenMenu.cs +++ b/Dalamud/Interface/TitleScreenMenu/TitleScreenMenu.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -22,7 +22,7 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu /// internal const uint TextureSize = 64; - private readonly List entries = new(); + private readonly List entries = []; private TitleScreenMenuEntry[]? entriesView; [ServiceManager.ServiceConstructor] @@ -42,7 +42,7 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu { lock (this.entries) { - if (!this.entries.Any()) + if (this.entries.Count == 0) return Array.Empty(); return this.entriesView ??= this.entries.OrderByDescending(x => x.IsInternal).ToArray(); @@ -59,7 +59,7 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu { lock (this.entries) { - if (!this.entries.Any()) + if (this.entries.Count == 0) return Array.Empty(); return this.entriesView ??= this.entries.OrderByDescending(x => x.IsInternal).ToArray(); @@ -81,7 +81,7 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu lock (this.entries) { var entriesOfAssembly = this.entries.Where(x => x.CallingAssembly == Assembly.GetCallingAssembly()).ToList(); - var priority = entriesOfAssembly.Any() + var priority = entriesOfAssembly.Count != 0 ? unchecked(entriesOfAssembly.Select(x => x.Priority).Max() + 1) : 0; entry = new(Assembly.GetCallingAssembly(), priority, text, texture, onTriggered); @@ -191,7 +191,7 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu lock (this.entries) { var entriesOfAssembly = this.entries.Where(x => x.CallingAssembly == null).ToList(); - var priority = entriesOfAssembly.Any() + var priority = entriesOfAssembly.Count != 0 ? unchecked(entriesOfAssembly.Select(x => x.Priority).Max() + 1) : 0; entry = new(null, priority, text, texture, onTriggered, showConditionKeys) @@ -220,7 +220,7 @@ internal class TitleScreenMenuPluginScoped : IInternalDisposableService, ITitleS [ServiceManager.ServiceDependency] private readonly TitleScreenMenu titleScreenMenuService = Service.Get(); - private readonly List pluginEntries = new(); + private readonly List pluginEntries = []; /// public IReadOnlyList? Entries => this.titleScreenMenuService.Entries; diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs index ea0e21e97..d2b4b655e 100644 --- a/Dalamud/Interface/UiBuilder.cs +++ b/Dalamud/Interface/UiBuilder.cs @@ -15,6 +15,7 @@ using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.ManagedFontAtlas.Internals; using Dalamud.Plugin.Internal.Types; using Dalamud.Utility; + using Serilog; namespace Dalamud.Interface; @@ -601,7 +602,7 @@ public sealed class UiBuilder : IDisposable, IUiBuilder /// /// Gets or sets a history of the last draw times, used to calculate an average. /// - internal List DrawTimeHistory { get; set; } = new List(); + internal List DrawTimeHistory { get; set; } = []; private InterfaceManager? InterfaceManagerWithScene => Service.GetNullable()?.Manager; diff --git a/Dalamud/Interface/UldWrapper.cs b/Dalamud/Interface/UldWrapper.cs index 85a2d8344..48c6a114d 100644 --- a/Dalamud/Interface/UldWrapper.cs +++ b/Dalamud/Interface/UldWrapper.cs @@ -7,6 +7,7 @@ using Dalamud.Interface.Textures; using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Utility; + using Lumina.Data.Files; using Lumina.Data.Parsing.Uld; @@ -17,7 +18,7 @@ public class UldWrapper : IDisposable { private readonly DataManager data; private readonly TextureManager textureManager; - private readonly Dictionary textures = new(); + private readonly Dictionary textures = []; /// Initializes a new instance of the class, wrapping an ULD file. /// The UiBuilder used to load textures. diff --git a/Dalamud/Interface/Utility/Internal/DevTextureSaveMenu.cs b/Dalamud/Interface/Utility/Internal/DevTextureSaveMenu.cs index 4a0137c88..7fcf795aa 100644 --- a/Dalamud/Interface/Utility/Internal/DevTextureSaveMenu.cs +++ b/Dalamud/Interface/Utility/Internal/DevTextureSaveMenu.cs @@ -14,7 +14,9 @@ using Dalamud.Interface.Internal; using Dalamud.Interface.Internal.Windows.Data.Widgets; using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Textures.TextureWraps; + using Serilog; + using TerraFX.Interop.Windows; namespace Dalamud.Interface.Utility.Internal; diff --git a/Dalamud/Interface/Utility/Raii/Color.cs b/Dalamud/Interface/Utility/Raii/Color.cs index 7bf2efc38..9682b929e 100644 --- a/Dalamud/Interface/Utility/Raii/Color.cs +++ b/Dalamud/Interface/Utility/Raii/Color.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Numerics; using Dalamud.Bindings.ImGui; -using Dalamud.Utility; namespace Dalamud.Interface.Utility.Raii; @@ -29,7 +28,7 @@ public static partial class ImRaii public sealed class Color : IDisposable { - internal static readonly List<(ImGuiCol, uint)> Stack = new(); + internal static readonly List<(ImGuiCol, uint)> Stack = []; private int count; public Color Push(ImGuiCol idx, uint color, bool condition = true) diff --git a/Dalamud/Interface/Utility/Raii/EndObjects.cs b/Dalamud/Interface/Utility/Raii/EndObjects.cs index 80122360c..80ae495e2 100644 --- a/Dalamud/Interface/Utility/Raii/EndObjects.cs +++ b/Dalamud/Interface/Utility/Raii/EndObjects.cs @@ -193,8 +193,8 @@ public static partial class ImRaii return new EndUnconditionally(Restore, true); } - private static IEndObject DisabledEnd() - => new EndUnconditionally(() => + private static EndUnconditionally DisabledEnd() + => new(() => { --disabledCount; ImGui.EndDisabled(); diff --git a/Dalamud/Interface/Utility/Raii/Font.cs b/Dalamud/Interface/Utility/Raii/Font.cs index da35c693a..1b5e8cc58 100644 --- a/Dalamud/Interface/Utility/Raii/Font.cs +++ b/Dalamud/Interface/Utility/Raii/Font.cs @@ -1,5 +1,4 @@ using Dalamud.Bindings.ImGui; -using Dalamud.Utility; namespace Dalamud.Interface.Utility.Raii; diff --git a/Dalamud/Interface/Utility/Raii/Plot.cs b/Dalamud/Interface/Utility/Raii/Plot.cs index d2ff38299..e88919e48 100644 --- a/Dalamud/Interface/Utility/Raii/Plot.cs +++ b/Dalamud/Interface/Utility/Raii/Plot.cs @@ -96,7 +96,7 @@ public static partial class ImRaii public sealed class PlotStyle : IDisposable { - internal static readonly List<(ImPlotStyleVar, Vector2)> Stack = new(); + internal static readonly List<(ImPlotStyleVar, Vector2)> Stack = []; private int count; @@ -249,7 +249,7 @@ public static partial class ImRaii public sealed class PlotColor : IDisposable { - internal static readonly List<(ImPlotCol, uint)> Stack = new(); + internal static readonly List<(ImPlotCol, uint)> Stack = []; private int count; // Reimplementation of https://github.com/ocornut/imgui/blob/868facff9ded2d61425c67deeba354eb24275bd1/imgui.cpp#L3035 diff --git a/Dalamud/Interface/Utility/Raii/Style.cs b/Dalamud/Interface/Utility/Raii/Style.cs index bfd04ea3c..e178b68d3 100644 --- a/Dalamud/Interface/Utility/Raii/Style.cs +++ b/Dalamud/Interface/Utility/Raii/Style.cs @@ -35,7 +35,7 @@ public static partial class ImRaii public sealed class Style : IDisposable { - internal static readonly List<(ImGuiStyleVar, Vector2)> Stack = new(); + internal static readonly List<(ImGuiStyleVar, Vector2)> Stack = []; private int count; diff --git a/Dalamud/Interface/Windowing/Persistence/PresetModel.cs b/Dalamud/Interface/Windowing/Persistence/PresetModel.cs index 4ddf55e51..1c6a93c16 100644 --- a/Dalamud/Interface/Windowing/Persistence/PresetModel.cs +++ b/Dalamud/Interface/Windowing/Persistence/PresetModel.cs @@ -25,7 +25,7 @@ internal class PresetModel /// Gets or sets a dictionary containing the windows in the preset, mapping their ID to the preset. /// [JsonProperty("w")] - public Dictionary Windows { get; set; } = new(); + public Dictionary Windows { get; set; } = []; /// /// Class representing a window in a preset. diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs index 5a79a017a..3cbd1a521 100644 --- a/Dalamud/Interface/Windowing/Window.cs +++ b/Dalamud/Interface/Windowing/Window.cs @@ -1,9 +1,11 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Numerics; using System.Threading.Tasks; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Keys; using Dalamud.Interface.Colors; @@ -33,7 +35,7 @@ public abstract class Window private const float FadeInOutTime = 0.072f; private const string AdditionsPopupName = "WindowSystemContextActions"; - private static readonly ModuleLog Log = new("WindowSystem"); + private static readonly ModuleLog Log = ModuleLog.Create(); private static bool wasEscPressedLastFrame = false; @@ -261,7 +263,7 @@ public abstract class Window /// disabled globally by the user, an internal title bar button to manage these is added when drawing, but it will /// not appear in this collection. If you wish to remove this button, set both of these values to false. /// - public List TitleBarButtons { get; set; } = new(); + public List TitleBarButtons { get; set; } = []; /// /// Gets or sets a value indicating whether this window will stay open. diff --git a/Dalamud/Interface/Windowing/WindowSystem.cs b/Dalamud/Interface/Windowing/WindowSystem.cs index d6e9649bb..319640336 100644 --- a/Dalamud/Interface/Windowing/WindowSystem.cs +++ b/Dalamud/Interface/Windowing/WindowSystem.cs @@ -4,6 +4,7 @@ using System.Linq; using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Interface.Windowing.Persistence; + using Serilog; namespace Dalamud.Interface.Windowing; @@ -15,7 +16,7 @@ public class WindowSystem { private static DateTimeOffset lastAnyFocus; - private readonly List windows = new(); + private readonly List windows = []; private string lastFocusedWindowName = string.Empty; diff --git a/Dalamud/IoC/Internal/ObjectInstance.cs b/Dalamud/IoC/Internal/ObjectInstance.cs index 3a963f6bd..af97b7124 100644 --- a/Dalamud/IoC/Internal/ObjectInstance.cs +++ b/Dalamud/IoC/Internal/ObjectInstance.cs @@ -1,4 +1,3 @@ -using System.Reflection; using System.Threading.Tasks; namespace Dalamud.IoC.Internal; diff --git a/Dalamud/IoC/Internal/ServiceContainer.cs b/Dalamud/IoC/Internal/ServiceContainer.cs index 6383b6b11..0dacacc54 100644 --- a/Dalamud/IoC/Internal/ServiceContainer.cs +++ b/Dalamud/IoC/Internal/ServiceContainer.cs @@ -20,10 +20,10 @@ namespace Dalamud.IoC.Internal; [ServiceManager.ProvidedService] internal class ServiceContainer : IServiceType { - private static readonly ModuleLog Log = new("SERVICECONTAINER"); + private static readonly ModuleLog Log = ModuleLog.Create(); - private readonly Dictionary instances = new(); - private readonly Dictionary interfaceToTypeMap = new(); + private readonly Dictionary instances = []; + private readonly Dictionary interfaceToTypeMap = []; /// /// Initializes a new instance of the class. diff --git a/Dalamud/Localization.cs b/Dalamud/Localization.cs index 0a7086e73..8c7368c3f 100644 --- a/Dalamud/Localization.cs +++ b/Dalamud/Localization.cs @@ -18,7 +18,7 @@ public class Localization : IServiceType /// /// Array of language codes which have a valid translation in Dalamud. /// - public static readonly string[] ApplicableLangCodes = { "de", "ja", "fr", "it", "es", "ko", "no", "ru", "zh", "tw" }; + public static readonly string[] ApplicableLangCodes = ["de", "ja", "fr", "it", "es", "ko", "no", "ru", "zh", "tw"]; private const string FallbackLangCode = "en"; diff --git a/Dalamud/Logging/Internal/TaskTracker.cs b/Dalamud/Logging/Internal/TaskTracker.cs index cb9a0db6d..c6bd895a0 100644 --- a/Dalamud/Logging/Internal/TaskTracker.cs +++ b/Dalamud/Logging/Internal/TaskTracker.cs @@ -15,8 +15,8 @@ namespace Dalamud.Logging.Internal; [ServiceManager.EarlyLoadedService] internal class TaskTracker : IInternalDisposableService { - private static readonly ModuleLog Log = new("TT"); - private static readonly List TrackedTasksInternal = new(); + private static readonly ModuleLog Log = ModuleLog.Create(); + private static readonly List TrackedTasksInternal = []; private static readonly ConcurrentQueue NewlyCreatedTasks = new(); private static bool clearRequested = false; diff --git a/Dalamud/Memory/MemoryHelper.cs b/Dalamud/Memory/MemoryHelper.cs index 2eae1be6d..d23b67e4f 100644 --- a/Dalamud/Memory/MemoryHelper.cs +++ b/Dalamud/Memory/MemoryHelper.cs @@ -6,11 +6,15 @@ using System.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Memory.Exceptions; using Dalamud.Utility; + using FFXIVClientStructs.FFXIV.Client.System.Memory; using FFXIVClientStructs.FFXIV.Client.System.String; + using Lumina.Text.Payloads; using Lumina.Text.ReadOnly; + using Microsoft.Extensions.ObjectPool; + using Windows.Win32.Foundation; using Windows.Win32.System.Memory; diff --git a/Dalamud/Networking/Http/HappyEyeballsCallback.cs b/Dalamud/Networking/Http/HappyEyeballsCallback.cs index 4e3ee61f6..59bdff630 100644 --- a/Dalamud/Networking/Http/HappyEyeballsCallback.cs +++ b/Dalamud/Networking/Http/HappyEyeballsCallback.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; @@ -20,7 +20,7 @@ namespace Dalamud.Networking.Http; /// public class HappyEyeballsCallback : IDisposable { - private static readonly ModuleLog Log = new("HTTP"); + private static readonly ModuleLog Log = ModuleLog.Create(); /* * ToDo: Eventually add in some kind of state management to cache DNS and IP Family. diff --git a/Dalamud/Plugin/DalamudPluginInterface.cs b/Dalamud/Plugin/DalamudPluginInterface.cs index e42bbe608..df1d0f6e9 100644 --- a/Dalamud/Plugin/DalamudPluginInterface.cs +++ b/Dalamud/Plugin/DalamudPluginInterface.cs @@ -342,7 +342,7 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa { var mi = this.configs.GetType().GetMethod("LoadForType"); var fn = mi.MakeGenericMethod(type); - return (IPluginConfiguration)fn.Invoke(this.configs, new object[] { this.plugin.InternalName }); + return (IPluginConfiguration)fn.Invoke(this.configs, [this.plugin.InternalName]); } } diff --git a/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs b/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs index 3fc011a68..734bc5ef9 100644 --- a/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs +++ b/Dalamud/Plugin/Internal/AutoUpdate/AutoUpdateManager.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using CheapLoc; + using Dalamud.Bindings.ImGui; using Dalamud.Configuration.Internal; using Dalamud.Console; @@ -32,7 +33,7 @@ namespace Dalamud.Plugin.Internal.AutoUpdate; [ServiceManager.EarlyLoadedService] internal class AutoUpdateManager : IServiceType { - private static readonly ModuleLog Log = new("AUTOUPDATE"); + private static readonly ModuleLog Log = ModuleLog.Create(); /// /// Time we should wait after login to update. @@ -376,7 +377,7 @@ internal class AutoUpdateManager : IServiceType } } - private void NotifyUpdatesAreAvailable(ICollection updatablePlugins) + private void NotifyUpdatesAreAvailable(List updatablePlugins) { if (updatablePlugins.Count == 0) return; diff --git a/Dalamud/Plugin/Internal/Loader/AssemblyLoadContextBuilder.cs b/Dalamud/Plugin/Internal/Loader/AssemblyLoadContextBuilder.cs index 1c6e6feed..aa304cd05 100644 --- a/Dalamud/Plugin/Internal/Loader/AssemblyLoadContextBuilder.cs +++ b/Dalamud/Plugin/Internal/Loader/AssemblyLoadContextBuilder.cs @@ -15,9 +15,9 @@ namespace Dalamud.Plugin.Internal.Loader; /// internal class AssemblyLoadContextBuilder { - private readonly List additionalProbingPaths = new(); - private readonly List resourceProbingPaths = new(); - private readonly List resourceProbingSubpaths = new(); + private readonly List additionalProbingPaths = []; + private readonly List resourceProbingPaths = []; + private readonly List resourceProbingSubpaths = []; private readonly Dictionary managedLibraries = new(StringComparer.Ordinal); private readonly Dictionary nativeLibraries = new(StringComparer.Ordinal); private readonly HashSet privateAssemblies = new(StringComparer.Ordinal); @@ -140,7 +140,7 @@ internal class AssemblyLoadContextBuilder return this; } - var names = new Queue(new[] { assemblyName }); + var names = new Queue([assemblyName]); while (names.TryDequeue(out var name)) { diff --git a/Dalamud/Plugin/Internal/Loader/LoaderConfig.cs b/Dalamud/Plugin/Internal/Loader/LoaderConfig.cs index b863b8ee1..e26338820 100644 --- a/Dalamud/Plugin/Internal/Loader/LoaderConfig.cs +++ b/Dalamud/Plugin/Internal/Loader/LoaderConfig.cs @@ -39,13 +39,13 @@ internal class LoaderConfig /// /// Gets a list of assemblies which should be treated as private. /// - public ICollection PrivateAssemblies { get; } = new List(); + public ICollection PrivateAssemblies { get; } = []; /// /// Gets a list of assemblies which should be unified between the host and the plugin. /// /// what-are-shared-types - public ICollection<(AssemblyName Name, bool Recursive)> SharedAssemblies { get; } = new List<(AssemblyName Name, bool Recursive)>(); + public ICollection<(AssemblyName Name, bool Recursive)> SharedAssemblies { get; } = []; /// /// Gets or sets a value indicating whether attempt to unify all types from a plugin with the host. diff --git a/Dalamud/Plugin/Internal/Loader/ManagedLoadContext.cs b/Dalamud/Plugin/Internal/Loader/ManagedLoadContext.cs index 4ea4eb5c4..a85d20e40 100644 --- a/Dalamud/Plugin/Internal/Loader/ManagedLoadContext.cs +++ b/Dalamud/Plugin/Internal/Loader/ManagedLoadContext.cs @@ -24,7 +24,7 @@ internal class ManagedLoadContext : AssemblyLoadContext private readonly IReadOnlyDictionary managedAssemblies; private readonly IReadOnlyDictionary nativeLibraries; private readonly IReadOnlyCollection privateAssemblies; - private readonly ICollection defaultAssemblies; + private readonly List defaultAssemblies; private readonly IReadOnlyCollection additionalProbingPaths; private readonly bool preferDefaultLoadContext; private readonly string[] resourceRoots; @@ -64,8 +64,7 @@ internal class ManagedLoadContext : AssemblyLoadContext bool shadowCopyNativeLibraries) : base(Path.GetFileNameWithoutExtension(mainAssemblyPath), isCollectible) { - if (resourceProbingPaths == null) - throw new ArgumentNullException(nameof(resourceProbingPaths)); + ArgumentNullException.ThrowIfNull(resourceProbingPaths); this.mainAssemblyPath = mainAssemblyPath ?? throw new ArgumentNullException(nameof(mainAssemblyPath)); this.dependencyResolver = new AssemblyDependencyResolver(mainAssemblyPath); @@ -243,7 +242,7 @@ internal class ManagedLoadContext : AssemblyLoadContext } // check to see if there is a library entry for the library without the file extension - var trimmedName = unmanagedDllName.Substring(0, unmanagedDllName.Length - suffix.Length); + var trimmedName = unmanagedDllName[..^suffix.Length]; if (this.nativeLibraries.TryGetValue(prefix + trimmedName, out library)) { diff --git a/Dalamud/Plugin/Internal/Loader/PlatformInformation.cs b/Dalamud/Plugin/Internal/Loader/PlatformInformation.cs index ec1d557be..151d184db 100644 --- a/Dalamud/Plugin/Internal/Loader/PlatformInformation.cs +++ b/Dalamud/Plugin/Internal/Loader/PlatformInformation.cs @@ -11,21 +11,21 @@ internal class PlatformInformation /// /// Gets a list of native OS specific library extensions. /// - public static string[] NativeLibraryExtensions => new[] { ".dll" }; + public static string[] NativeLibraryExtensions => [".dll"]; /// /// Gets a list of native OS specific library prefixes. /// - public static string[] NativeLibraryPrefixes => new[] { string.Empty }; + public static string[] NativeLibraryPrefixes => [string.Empty]; /// /// Gets a list of native OS specific managed assembly extensions. /// - public static string[] ManagedAssemblyExtensions => new[] - { + public static string[] ManagedAssemblyExtensions => + [ ".dll", ".ni.dll", ".exe", ".ni.exe", - }; + ]; } diff --git a/Dalamud/Plugin/Internal/Loader/PluginLoader.cs b/Dalamud/Plugin/Internal/Loader/PluginLoader.cs index 54b9cad4b..a77bfe088 100644 --- a/Dalamud/Plugin/Internal/Loader/PluginLoader.cs +++ b/Dalamud/Plugin/Internal/Loader/PluginLoader.cs @@ -53,8 +53,7 @@ internal class PluginLoader : IDisposable /// A loader. public static PluginLoader CreateFromAssemblyFile(string assemblyFile, Action configure) { - if (configure == null) - throw new ArgumentNullException(nameof(configure)); + ArgumentNullException.ThrowIfNull(configure); var config = new LoaderConfig(assemblyFile); configure(config); @@ -159,7 +158,6 @@ internal class PluginLoader : IDisposable private void EnsureNotDisposed() { - if (this.disposed) - throw new ObjectDisposedException(nameof(PluginLoader)); + ObjectDisposedException.ThrowIf(this.disposed, this); } } diff --git a/Dalamud/Plugin/Internal/PluginErrorHandler.cs b/Dalamud/Plugin/Internal/PluginErrorHandler.cs index 0094c3751..6733cc3ca 100644 --- a/Dalamud/Plugin/Internal/PluginErrorHandler.cs +++ b/Dalamud/Plugin/Internal/PluginErrorHandler.cs @@ -22,7 +22,7 @@ internal class PluginErrorHandler : IServiceType private readonly NotificationManager notificationManager; private readonly DalamudInterface di; - private readonly Dictionary invokerCache = new(); + private readonly Dictionary invokerCache = []; private DateTime lastErrorTime = DateTime.MinValue; private IActiveNotification? activeNotification; @@ -141,10 +141,7 @@ internal class PluginErrorHandler : IServiceType private static Action CreateInvoker() where TDelegate : Delegate { var delegateType = typeof(TDelegate); - var method = delegateType.GetMethod("Invoke"); - if (method == null) - throw new InvalidOperationException($"Delegate {delegateType} does not have an Invoke method."); - + var method = delegateType.GetMethod("Invoke") ?? throw new InvalidOperationException($"Delegate {delegateType} does not have an Invoke method."); var parameters = method.GetParameters(); // Create parameters for the lambda @@ -153,7 +150,7 @@ internal class PluginErrorHandler : IServiceType // Create expressions to convert array elements to parameter types var callArgs = new Expression[parameters.Length]; - for (int i = 0; i < parameters.Length; i++) + for (var i = 0; i < parameters.Length; i++) { var paramType = parameters[i].ParameterType; var arrayAccess = Expression.ArrayIndex(argsParam, Expression.Constant(i)); diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index 193a2d45f..0c9894380 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -11,6 +11,7 @@ using System.Threading; using System.Threading.Tasks; using CheapLoc; + using Dalamud.Configuration; using Dalamud.Configuration.Internal; using Dalamud.Game; @@ -31,6 +32,7 @@ using Dalamud.Plugin.Ipc.Internal; using Dalamud.Support; using Dalamud.Utility; using Dalamud.Utility.Timing; + using Newtonsoft.Json; namespace Dalamud.Plugin.Internal; @@ -56,9 +58,9 @@ internal class PluginManager : IInternalDisposableService private readonly DirectoryInfo pluginDirectory; private readonly BannedPlugin[]? bannedPlugins; - private readonly List installedPluginsList = new(); - private readonly List availablePluginsList = new(); - private readonly List updatablePluginsList = new(); + private readonly List installedPluginsList = []; + private readonly List availablePluginsList = []; + private readonly List updatablePluginsList = []; private readonly Task openInstallerWindowPluginChangelogsLink; @@ -131,7 +133,7 @@ internal class PluginManager : IInternalDisposableService PluginInstallerOpenKind.Changelogs); })); - this.configuration.PluginTestingOptIns ??= new(); + this.configuration.PluginTestingOptIns ??= []; this.MainRepo = PluginRepository.CreateMainRepo(this.happyHttpClient); registerStartupBlocker( @@ -230,7 +232,7 @@ internal class PluginManager : IInternalDisposableService /// /// Gets a list of all plugin repositories. The main repo should always be first. /// - public List Repos { get; private set; } = new(); + public List Repos { get; private set; } = []; /// /// Gets a value indicating whether plugins are not still loading from boot. @@ -1514,11 +1516,7 @@ internal class PluginManager : IInternalDisposableService JsonConvert.SerializeObject(repoManifest, Formatting.Indented)); // Reload as a local manifest, add some attributes, and save again. - var tempManifest = LocalPluginManifest.Load(tempManifestFile); - - if (tempManifest == null) - throw new Exception("Plugin had no valid manifest"); - + var tempManifest = LocalPluginManifest.Load(tempManifestFile) ?? throw new Exception("Plugin had no valid manifest"); if (tempManifest.InternalName != repoManifest.InternalName) { throw new Exception( @@ -1897,9 +1895,9 @@ internal class PluginManager : IInternalDisposableService /// public class StartupLoadTracker { - private readonly Dictionary internalToPublic = new(); - private readonly ConcurrentBag allInternalNames = new(); - private readonly ConcurrentBag finishedInternalNames = new(); + private readonly Dictionary internalToPublic = []; + private readonly ConcurrentBag allInternalNames = []; + private readonly ConcurrentBag finishedInternalNames = []; /// /// Gets a value indicating the total load progress. diff --git a/Dalamud/Plugin/Internal/PluginValidator.cs b/Dalamud/Plugin/Internal/PluginValidator.cs index b2cbe5520..4c6bb9fef 100644 --- a/Dalamud/Plugin/Internal/PluginValidator.cs +++ b/Dalamud/Plugin/Internal/PluginValidator.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Dalamud.Game.Command; @@ -11,7 +11,7 @@ namespace Dalamud.Plugin.Internal; /// internal static class PluginValidator { - private static readonly char[] LineSeparator = new[] { ' ', '\n', '\r' }; + private static readonly char[] LineSeparator = [' ', '\n', '\r']; /// /// Represents the severity of a validation problem. diff --git a/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs b/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs index 09cceebcb..6608f2669 100644 --- a/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs +++ b/Dalamud/Plugin/Internal/Profiles/PluginManagementCommandHandler.cs @@ -3,12 +3,14 @@ using System.Linq; using System.Threading.Tasks; using CheapLoc; + using Dalamud.Game; using Dalamud.Game.Command; using Dalamud.Game.Gui; using Dalamud.Plugin.Internal.Types; using Dalamud.Plugin.Services; using Dalamud.Utility; + using Serilog; namespace Dalamud.Plugin.Internal.Profiles; @@ -39,7 +41,7 @@ internal class PluginManagementCommandHandler : IInternalDisposableService private readonly ChatGui chat; private readonly Framework framework; - private List<(Target Target, PluginCommandOperation Operation)> commandQueue = new(); + private List<(Target Target, PluginCommandOperation Operation)> commandQueue = []; /// /// Initializes a new instance of the class. diff --git a/Dalamud/Plugin/Internal/Profiles/Profile.cs b/Dalamud/Plugin/Internal/Profiles/Profile.cs index d899b0cca..9d931d9ed 100644 --- a/Dalamud/Plugin/Internal/Profiles/Profile.cs +++ b/Dalamud/Plugin/Internal/Profiles/Profile.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -14,7 +14,7 @@ namespace Dalamud.Plugin.Internal.Profiles; /// internal class Profile { - private static readonly ModuleLog Log = new("PROFILE"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly ProfileManager manager; private readonly ProfileModelV1 modelV1; diff --git a/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs b/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs index 775ff7a72..bbe678162 100644 --- a/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs +++ b/Dalamud/Plugin/Internal/Profiles/ProfileManager.cs @@ -1,10 +1,11 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using CheapLoc; + using Dalamud.Configuration.Internal; using Dalamud.Logging.Internal; using Dalamud.Utility; @@ -15,12 +16,12 @@ namespace Dalamud.Plugin.Internal.Profiles; /// Class responsible for managing plugin profiles. /// [ServiceManager.BlockingEarlyLoadedService($"Data provider for {nameof(PluginManager)}.")] -internal class ProfileManager : IServiceType +internal partial class ProfileManager : IServiceType { - private static readonly ModuleLog Log = new("PROFMAN"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly DalamudConfiguration config; - private readonly List profiles = new(); + private readonly List profiles = []; private volatile bool isBusy = false; @@ -151,11 +152,7 @@ internal class ProfileManager : IServiceType /// The newly cloned profile. public Profile CloneProfile(Profile toClone) { - var newProfile = this.ImportProfile(toClone.Model.SerializeForShare()); - if (newProfile == null) - throw new Exception("New profile was null while cloning"); - - return newProfile; + return this.ImportProfile(toClone.Model.SerializeForShare()) ?? throw new Exception("New profile was null while cloning"); } /// @@ -338,12 +335,15 @@ internal class ProfileManager : IServiceType } } + [GeneratedRegex(@" \(.* Mix\)")] + private static partial Regex MixRegex(); + private string GenerateUniqueProfileName(string startingWith) { if (this.profiles.All(x => x.Name != startingWith)) return startingWith; - startingWith = Regex.Replace(startingWith, @" \(.* Mix\)", string.Empty); + startingWith = MixRegex().Replace(startingWith, string.Empty); while (true) { @@ -359,7 +359,7 @@ internal class ProfileManager : IServiceType this.config.DefaultProfile ??= new ProfileModelV1(); this.profiles.Add(new Profile(this, this.config.DefaultProfile, true, true)); - this.config.SavedProfiles ??= new List(); + this.config.SavedProfiles ??= []; foreach (var profileModel in this.config.SavedProfiles) { this.profiles.Add(new Profile(this, profileModel, false, true)); diff --git a/Dalamud/Plugin/Internal/Profiles/ProfileModel.cs b/Dalamud/Plugin/Internal/Profiles/ProfileModel.cs index e3d9e2955..37487e321 100644 --- a/Dalamud/Plugin/Internal/Profiles/ProfileModel.cs +++ b/Dalamud/Plugin/Internal/Profiles/ProfileModel.cs @@ -1,7 +1,8 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Reflection; using Dalamud.Utility; + using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -32,7 +33,7 @@ public abstract class ProfileModel /// Thrown when the parsed string is not a valid profile. public static ProfileModel? Deserialize(string model) { - var json = Util.DecompressString(Convert.FromBase64String(model.Substring(3))); + var json = Util.DecompressString(Convert.FromBase64String(model[3..])); if (model.StartsWith(ProfileModelV1.SerializedPrefix)) return JsonConvert.DeserializeObject(json); @@ -47,19 +48,15 @@ public abstract class ProfileModel /// Thrown when an unsupported model is serialized. public string SerializeForShare() { - string prefix; - switch (this) + var prefix = this switch { - case ProfileModelV1: - prefix = ProfileModelV1.SerializedPrefix; - break; - default: - throw new ArgumentOutOfRangeException(); - } + ProfileModelV1 => ProfileModelV1.SerializedPrefix, + _ => throw new ArgumentOutOfRangeException(), + }; // HACK: Just filter the ID for now, we should split the sharing + saving model var serialized = JsonConvert.SerializeObject(this, new JsonSerializerSettings() - { ContractResolver = new IgnorePropertiesResolver(new[] { "WorkingPluginId" }) }); + { ContractResolver = new IgnorePropertiesResolver(["WorkingPluginId"]) }); return prefix + Convert.ToBase64String(Util.CompressString(serialized)); } diff --git a/Dalamud/Plugin/Internal/Profiles/ProfileModelV1.cs b/Dalamud/Plugin/Internal/Profiles/ProfileModelV1.cs index a1a327c1d..deee9c04f 100644 --- a/Dalamud/Plugin/Internal/Profiles/ProfileModelV1.cs +++ b/Dalamud/Plugin/Internal/Profiles/ProfileModelV1.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Newtonsoft.Json; @@ -63,7 +63,7 @@ public class ProfileModelV1 : ProfileModel /// /// Gets or sets the list of plugins in this profile. /// - public List Plugins { get; set; } = new(); + public List Plugins { get; set; } = []; /// /// Class representing a single plugin in a profile. diff --git a/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs index 34b54163a..2e20d2aef 100644 --- a/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs @@ -17,7 +17,7 @@ namespace Dalamud.Plugin.Internal.Types; /// internal sealed class LocalDevPlugin : LocalPlugin { - private static readonly ModuleLog Log = new("PLUGIN"); + private static readonly ModuleLog Log = ModuleLog.Create(); // Ref to Dalamud.Configuration.DevPluginSettings private readonly DevPluginSettings devSettings; diff --git a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs index 1fe18b95b..29867b355 100644 --- a/Dalamud/Plugin/Internal/Types/LocalPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalPlugin.cs @@ -33,7 +33,7 @@ internal class LocalPlugin : IAsyncDisposable protected LocalPluginManifest manifest; #pragma warning restore SA1401 - private static readonly ModuleLog Log = new("LOCALPLUGIN"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly FileInfo manifestFile; private readonly FileInfo disabledFile; diff --git a/Dalamud/Plugin/Internal/Types/Manifest/LocalPluginManifest.cs b/Dalamud/Plugin/Internal/Types/Manifest/LocalPluginManifest.cs index 3aededa18..73d23d19f 100644 --- a/Dalamud/Plugin/Internal/Types/Manifest/LocalPluginManifest.cs +++ b/Dalamud/Plugin/Internal/Types/Manifest/LocalPluginManifest.cs @@ -1,7 +1,9 @@ using System.IO; using Dalamud.Utility; + using Newtonsoft.Json; + using Serilog; namespace Dalamud.Plugin.Internal.Types.Manifest; diff --git a/Dalamud/Plugin/Internal/Types/Manifest/RemotePluginManifest.cs b/Dalamud/Plugin/Internal/Types/Manifest/RemotePluginManifest.cs index 47e92cd84..b83ba91a8 100644 --- a/Dalamud/Plugin/Internal/Types/Manifest/RemotePluginManifest.cs +++ b/Dalamud/Plugin/Internal/Types/Manifest/RemotePluginManifest.cs @@ -1,4 +1,5 @@ using JetBrains.Annotations; + using Newtonsoft.Json; namespace Dalamud.Plugin.Internal.Types.Manifest; diff --git a/Dalamud/Plugin/Internal/Types/PluginDef.cs b/Dalamud/Plugin/Internal/Types/PluginDef.cs index 25cd82423..f9f49225a 100644 --- a/Dalamud/Plugin/Internal/Types/PluginDef.cs +++ b/Dalamud/Plugin/Internal/Types/PluginDef.cs @@ -7,7 +7,7 @@ namespace Dalamud.Plugin.Internal.Types; /// /// Plugin Definition. /// -internal struct PluginDef +internal readonly struct PluginDef { /// /// Initializes a new instance of the struct. diff --git a/Dalamud/Plugin/Internal/Types/PluginManifest.cs b/Dalamud/Plugin/Internal/Types/PluginManifest.cs index cbf69bb5e..fc9f4e372 100644 --- a/Dalamud/Plugin/Internal/Types/PluginManifest.cs +++ b/Dalamud/Plugin/Internal/Types/PluginManifest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Dalamud.Common.Game; using Dalamud.Plugin.Internal.Types.Manifest; + using Newtonsoft.Json; namespace Dalamud.Plugin.Internal.Types; diff --git a/Dalamud/Plugin/Internal/Types/PluginRepository.cs b/Dalamud/Plugin/Internal/Types/PluginRepository.cs index d5c1131af..d47a3727d 100644 --- a/Dalamud/Plugin/Internal/Types/PluginRepository.cs +++ b/Dalamud/Plugin/Internal/Types/PluginRepository.cs @@ -29,7 +29,7 @@ internal class PluginRepository private const int HttpRequestTimeoutSeconds = 20; - private static readonly ModuleLog Log = new("PLUGINR"); + private static readonly ModuleLog Log = ModuleLog.Create(); private readonly HttpClient httpClient; /// @@ -119,13 +119,7 @@ internal class PluginRepository response.EnsureSuccessStatusCode(); var data = await response.Content.ReadAsStringAsync(); - var pluginMaster = JsonConvert.DeserializeObject>(data); - - if (pluginMaster == null) - { - throw new Exception("Deserialized PluginMaster was null."); - } - + var pluginMaster = JsonConvert.DeserializeObject>(data) ?? throw new Exception("Deserialized PluginMaster was null."); pluginMaster.Sort((pm1, pm2) => string.Compare(pm1.Name, pm2.Name, StringComparison.Ordinal)); // Set the source for each remote manifest. Allows for checking if is 3rd party. diff --git a/Dalamud/Plugin/Ipc/ICallGateProvider.cs b/Dalamud/Plugin/Ipc/ICallGateProvider.cs index 387f0adf9..5fde2ef01 100644 --- a/Dalamud/Plugin/Ipc/ICallGateProvider.cs +++ b/Dalamud/Plugin/Ipc/ICallGateProvider.cs @@ -1,5 +1,4 @@ using Dalamud.Plugin.Ipc.Internal; -using Dalamud.Utility; #pragma warning disable SA1402 // File may only contain a single type diff --git a/Dalamud/Plugin/Ipc/Internal/CallGate.cs b/Dalamud/Plugin/Ipc/Internal/CallGate.cs index fef4b97d0..3f299da9d 100644 --- a/Dalamud/Plugin/Ipc/Internal/CallGate.cs +++ b/Dalamud/Plugin/Ipc/Internal/CallGate.cs @@ -9,7 +9,7 @@ namespace Dalamud.Plugin.Ipc.Internal; [ServiceManager.EarlyLoadedService] internal class CallGate : IServiceType { - private readonly Dictionary gates = new(); + private readonly Dictionary gates = []; private ImmutableDictionary? gatesCopy; diff --git a/Dalamud/Plugin/Ipc/Internal/CallGateChannel.cs b/Dalamud/Plugin/Ipc/Internal/CallGateChannel.cs index 8bd631b0e..78c7f841b 100644 --- a/Dalamud/Plugin/Ipc/Internal/CallGateChannel.cs +++ b/Dalamud/Plugin/Ipc/Internal/CallGateChannel.cs @@ -9,6 +9,7 @@ using Dalamud.Plugin.Ipc.Exceptions; using Dalamud.Plugin.Ipc.Internal.Converters; using Newtonsoft.Json; + using Serilog; namespace Dalamud.Plugin.Ipc.Internal; @@ -23,7 +24,7 @@ internal class CallGateChannel /// /// The actual storage. /// - private readonly HashSet subscriptions = new(); + private readonly HashSet subscriptions = []; /// /// A copy of the actual storage, that will be cleared and populated depending on changes made to diff --git a/Dalamud/Plugin/Ipc/Internal/DataCache.cs b/Dalamud/Plugin/Ipc/Internal/DataCache.cs index 38cea4866..d565c8b35 100644 --- a/Dalamud/Plugin/Ipc/Internal/DataCache.cs +++ b/Dalamud/Plugin/Ipc/Internal/DataCache.cs @@ -40,7 +40,7 @@ internal readonly struct DataCache { this.Tag = tag; this.CreatorAssemblyName = creatorAssemblyName; - this.UserAssemblyNames = new(); + this.UserAssemblyNames = []; this.Data = data; this.Type = type; } diff --git a/Dalamud/Plugin/Ipc/Internal/DataShare.cs b/Dalamud/Plugin/Ipc/Internal/DataShare.cs index 8ce5ddb95..becbe1211 100644 --- a/Dalamud/Plugin/Ipc/Internal/DataShare.cs +++ b/Dalamud/Plugin/Ipc/Internal/DataShare.cs @@ -19,7 +19,7 @@ internal class DataShare : IServiceType /// Dictionary of cached values. Note that is being used, as it does its own locking, /// effectively preventing calling the data generator multiple times concurrently. /// - private readonly Dictionary> caches = new(); + private readonly Dictionary> caches = []; [ServiceManager.ServiceConstructor] private DataShare() diff --git a/Dalamud/SafeMemory.cs b/Dalamud/SafeMemory.cs index ca0c8ff92..16d16056d 100644 --- a/Dalamud/SafeMemory.cs +++ b/Dalamud/SafeMemory.cs @@ -193,7 +193,7 @@ public static class SafeMemory return null; var data = encoding.GetString(buffer); var eosPos = data.IndexOf('\0'); - return eosPos == -1 ? data : data.Substring(0, eosPos); + return eosPos == -1 ? data : data[..eosPos]; } /// @@ -303,7 +303,7 @@ public static class SafeMemory return bytes; } - public T Read(int offset = 0) => (T)Marshal.PtrToStructure(this.hGlobal + offset, typeof(T)); + public T Read(int offset = 0) => Marshal.PtrToStructure(this.hGlobal + offset); public object? Read(Type type, int offset = 0) => Marshal.PtrToStructure(this.hGlobal + offset, type); diff --git a/Dalamud/Service/ServiceManager.cs b/Dalamud/Service/ServiceManager.cs index 88c6366fd..824f816ff 100644 --- a/Dalamud/Service/ServiceManager.cs +++ b/Dalamud/Service/ServiceManager.cs @@ -35,7 +35,7 @@ internal static class ServiceManager /// /// Static log facility for Service{T}, to avoid duplicate instances for different types. /// - public static readonly ModuleLog Log = new("SVC"); + public static readonly ModuleLog Log = new(nameof(ServiceManager)); #if DEBUG /// @@ -44,7 +44,7 @@ internal static class ServiceManager internal static readonly ThreadLocal CurrentConstructorServiceType = new(); [SuppressMessage("ReSharper", "CollectionNeverQueried.Local", Justification = "Debugging purposes")] - private static readonly List LoadedServices = new(); + private static readonly List LoadedServices = []; #endif private static readonly TaskCompletionSource BlockingServicesLoadedTaskCompletionSource = @@ -291,7 +291,7 @@ internal static class ServiceManager await loadingDialog.HideAndJoin(); return; - async Task WaitWithTimeoutConsent(IEnumerable tasksEnumerable, LoadingDialog.State state) + static async Task WaitWithTimeoutConsent(IEnumerable tasksEnumerable, LoadingDialog.State state) { loadingDialog.CurrentState = state; var tasks = tasksEnumerable.AsReadOnlyCollection(); @@ -317,7 +317,7 @@ internal static class ServiceManager servicesToLoad.UnionWith(earlyLoadingServices); servicesToLoad.UnionWith(blockingEarlyLoadingServices); - while (servicesToLoad.Any()) + while (servicesToLoad.Count != 0) { foreach (var serviceType in servicesToLoad) { @@ -367,7 +367,7 @@ internal static class ServiceManager BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic, null, null, - new object[] { startLoaderArgs })); + [startLoaderArgs])); servicesToLoad.Remove(serviceType); #if DEBUG @@ -383,23 +383,23 @@ internal static class ServiceManager #endif } - if (!tasks.Any()) + if (tasks.Count == 0) { // No more services we can start loading for now. // Either we're waiting for provided services, or there's a dependency cycle. providedServices.RemoveWhere(x => getAsyncTaskMap[x].IsCompleted); - if (providedServices.Any()) + if (providedServices.Count != 0) await Task.WhenAny(providedServices.Select(x => getAsyncTaskMap[x])); else throw new InvalidOperationException("Unresolvable dependency cycle detected"); continue; } - if (servicesToLoad.Any()) + if (servicesToLoad.Count != 0) { await Task.WhenAny(tasks); var faultedTasks = tasks.Where(x => x.IsFaulted).Select(x => (Exception)x.Exception!).ToArray(); - if (faultedTasks.Any()) + if (faultedTasks.Length != 0) throw new AggregateException(faultedTasks); } else @@ -426,7 +426,7 @@ internal static class ServiceManager await loadingDialog.HideAndJoin(); - while (tasks.Any()) + while (tasks.Count != 0) { await Task.WhenAny(tasks); tasks.RemoveAll(x => x.IsCompleted); diff --git a/Dalamud/Service/Service{T}.cs b/Dalamud/Service/Service{T}.cs index 1f5558893..c965eeb3d 100644 --- a/Dalamud/Service/Service{T}.cs +++ b/Dalamud/Service/Service{T}.cs @@ -206,7 +206,7 @@ internal static class Service where T : IServiceType is not ServiceManager.ServiceKind.BlockingEarlyLoadedService and not ServiceManager.ServiceKind.ProvidedService) .ToArray(); - if (offenders.Any()) + if (offenders.Length != 0) { const string bels = nameof(ServiceManager.BlockingEarlyLoadedServiceAttribute); const string ps = nameof(ServiceManager.ProvidedServiceAttribute); @@ -286,13 +286,13 @@ internal static class Service where T : IServiceType { if (method.Invoke(instance, args) is Task task) { - tasks ??= new(); + tasks ??= []; tasks.Add(task); } } catch (Exception e) { - tasks ??= new(); + tasks ??= []; tasks.Add(Task.FromException(e)); } } @@ -351,15 +351,12 @@ internal static class Service where T : IServiceType BindingFlags.CreateInstance | BindingFlags.OptionalParamBinding; return typeof(T) .GetConstructors(ctorBindingFlags) - .SingleOrDefault(x => x.GetCustomAttributes(typeof(ServiceManager.ServiceConstructor), true).Any()); + .SingleOrDefault(x => x.GetCustomAttributes(typeof(ServiceManager.ServiceConstructor), true).Length != 0); } private static async Task ConstructObject(IReadOnlyCollection additionalProvidedTypedObjects) { - var ctor = GetServiceConstructor(); - if (ctor == null) - throw new Exception($"Service \"{typeof(T).FullName}\" had no applicable constructor"); - + var ctor = GetServiceConstructor() ?? throw new Exception($"Service \"{typeof(T).FullName}\" had no applicable constructor"); var args = await ResolveInjectedParameters(ctor.GetParameters(), additionalProvidedTypedObjects) .ConfigureAwait(false); using (Timings.Start($"{typeof(T).Name} Construct")) @@ -460,7 +457,7 @@ internal static class ServiceHelpers BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.Public, null, null, - new object?[] { includeUnloadDependencies }) ?? new List(); + [includeUnloadDependencies]) ?? new List(); } /// diff --git a/Dalamud/Storage/Assets/IDalamudAssetManager.cs b/Dalamud/Storage/Assets/IDalamudAssetManager.cs index b4dc41bfd..8b74e4347 100644 --- a/Dalamud/Storage/Assets/IDalamudAssetManager.cs +++ b/Dalamud/Storage/Assets/IDalamudAssetManager.cs @@ -1,9 +1,8 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.IO; using System.Threading.Tasks; -using Dalamud.Interface.Internal; using Dalamud.Interface.Textures.TextureWraps; namespace Dalamud.Storage.Assets; diff --git a/Dalamud/Storage/ReliableFileStorage.cs b/Dalamud/Storage/ReliableFileStorage.cs index d9f8526c3..72cc598ae 100644 --- a/Dalamud/Storage/ReliableFileStorage.cs +++ b/Dalamud/Storage/ReliableFileStorage.cs @@ -1,9 +1,11 @@ -using System.IO; +using System.IO; using System.Text; +using System.Threading; using System.Threading.Tasks; using Dalamud.Logging.Internal; using Dalamud.Utility; + using SQLite; namespace Dalamud.Storage; @@ -25,9 +27,9 @@ namespace Dalamud.Storage; [ServiceManager.ProvidedService] internal class ReliableFileStorage : IInternalDisposableService { - private static readonly ModuleLog Log = new("VFS"); + private static readonly ModuleLog Log = ModuleLog.Create(); - private readonly object syncRoot = new(); + private readonly Lock syncRoot = new(); private SQLiteConnection? db; @@ -272,8 +274,9 @@ internal class ReliableFileStorage : IInternalDisposableService throw new FileNotFoundException("Backup database was not available"); var normalizedPath = NormalizePath(path); - var file = this.db.Table().FirstOrDefault(f => f.Path == normalizedPath && f.ContainerId == containerId); - return file == null ? throw new FileNotFoundException() : file.Data; + var file = this.db.Table().FirstOrDefault(f => f.Path == normalizedPath && f.ContainerId == containerId) + ?? throw new FileNotFoundException(); + return file.Data; } // If the file doesn't exist, immediately check the backup db diff --git a/Dalamud/Support/BugBait.cs b/Dalamud/Support/BugBait.cs index f0a98ca98..c37c4d2f8 100644 --- a/Dalamud/Support/BugBait.cs +++ b/Dalamud/Support/BugBait.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Dalamud.Networking.Http; using Dalamud.Plugin.Internal.Types.Manifest; using Dalamud.Utility; + using Newtonsoft.Json; namespace Dalamud.Support; diff --git a/Dalamud/Support/Troubleshooting.cs b/Dalamud/Support/Troubleshooting.cs index de529a29b..2dd0fb623 100644 --- a/Dalamud/Support/Troubleshooting.cs +++ b/Dalamud/Support/Troubleshooting.cs @@ -8,7 +8,9 @@ using Dalamud.Interface.Internal; using Dalamud.Plugin.Internal; using Dalamud.Plugin.Internal.Types.Manifest; using Dalamud.Utility; + using Newtonsoft.Json; + using Serilog; namespace Dalamud.Support; @@ -32,7 +34,7 @@ public static class Troubleshooting { LastException = exception; - var fixedContext = context?.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); + var fixedContext = context?.Split(['\r', '\n'], StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); try { @@ -127,7 +129,7 @@ public static class Troubleshooting public bool ForcedMinHook { get; set; } - public List ThirdRepo => new(); + public List ThirdRepo => []; public bool HasThirdRepo { get; set; } } diff --git a/Dalamud/Utility/ArrayExtensions.cs b/Dalamud/Utility/ArrayExtensions.cs index 5b6ce2332..5444468c6 100644 --- a/Dalamud/Utility/ArrayExtensions.cs +++ b/Dalamud/Utility/ArrayExtensions.cs @@ -115,8 +115,7 @@ internal static class ArrayExtensions if (count < 0 || startIndex > list.Count - count) throw new ArgumentOutOfRangeException(nameof(count), count, null); - if (match == null) - throw new ArgumentNullException(nameof(match)); + ArgumentNullException.ThrowIfNull(match); var endIndex = startIndex + count; for (var i = startIndex; i < endIndex; i++) @@ -138,8 +137,7 @@ internal static class ArrayExtensions /// public static int FindLastIndex(this IReadOnlyList list, int startIndex, int count, Predicate match) { - if (match == null) - throw new ArgumentNullException(nameof(match)); + ArgumentNullException.ThrowIfNull(match); if (list.Count == 0) { diff --git a/Dalamud/Utility/CultureFixes.cs b/Dalamud/Utility/CultureFixes.cs index 133e79c71..f37844206 100644 --- a/Dalamud/Utility/CultureFixes.cs +++ b/Dalamud/Utility/CultureFixes.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; namespace Dalamud.Utility; @@ -22,7 +22,7 @@ internal static class CultureFixes // This glyph is not present in any game fonts and not in the range for our Noto // so it will be rendered as a geta (=) instead. That's a hack, but it works and // doesn't look as weird. - CultureInfo PatchCulture(CultureInfo info) + static CultureInfo PatchCulture(CultureInfo info) { var newCulture = (CultureInfo)info.Clone(); diff --git a/Dalamud/Utility/DateTimeSpanExtensions.cs b/Dalamud/Utility/DateTimeSpanExtensions.cs index 3cf8975af..d60b17924 100644 --- a/Dalamud/Utility/DateTimeSpanExtensions.cs +++ b/Dalamud/Utility/DateTimeSpanExtensions.cs @@ -100,7 +100,7 @@ public static class DateTimeSpanExtensions private sealed class ParsedRelativeFormatStrings { - private readonly List<(float MinSeconds, string FormatString)> formatStrings = new(); + private readonly List<(float MinSeconds, string FormatString)> formatStrings = []; public ParsedRelativeFormatStrings(string value) { diff --git a/Dalamud/Utility/DiagnosticUtil.cs b/Dalamud/Utility/DiagnosticUtil.cs index 155d5cda7..d853a2668 100644 --- a/Dalamud/Utility/DiagnosticUtil.cs +++ b/Dalamud/Utility/DiagnosticUtil.cs @@ -1,8 +1,6 @@ -using System.Diagnostics; +using System.Diagnostics; using System.Linq; -using Dalamud.Bindings.ImGui; - namespace Dalamud.Utility; /// diff --git a/Dalamud/Utility/DisposeSafety.cs b/Dalamud/Utility/DisposeSafety.cs index 64d31048f..ac7ed07d7 100644 --- a/Dalamud/Utility/DisposeSafety.cs +++ b/Dalamud/Utility/DisposeSafety.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reactive.Disposables; @@ -92,7 +92,7 @@ public static class DisposeSafety new AggregateException( new[] { e }.Concat( (IEnumerable)r.Exception?.InnerExceptions - ?? new[] { new OperationCanceledException() }))); + ?? [new OperationCanceledException()]))); } } @@ -125,7 +125,7 @@ public static class DisposeSafety } catch (Exception de) { - exceptions ??= new(); + exceptions ??= []; exceptions.Add(de); } } @@ -140,7 +140,7 @@ public static class DisposeSafety /// public class ScopedFinalizer : IDisposeCallback, IAsyncDisposable { - private readonly List objects = new(); + private readonly List objects = []; /// public event Action? BeforeDispose; @@ -338,7 +338,7 @@ public static class DisposeSafety } catch (Exception ex) { - exceptions ??= new(); + exceptions ??= []; exceptions.Add(ex); } } @@ -402,7 +402,7 @@ public static class DisposeSafety } catch (Exception ex) { - exceptions ??= new(); + exceptions ??= []; exceptions.Add(ex); } } diff --git a/Dalamud/Utility/DynamicPriorityQueueLoader.cs b/Dalamud/Utility/DynamicPriorityQueueLoader.cs index 83fd366bb..c32858bb4 100644 --- a/Dalamud/Utility/DynamicPriorityQueueLoader.cs +++ b/Dalamud/Utility/DynamicPriorityQueueLoader.cs @@ -15,7 +15,7 @@ internal class DynamicPriorityQueueLoader : IDisposable private readonly Channel newItemChannel; private readonly Channel workTokenChannel; - private readonly List workItemPending = new(); + private readonly List workItemPending = []; private bool disposing; diff --git a/Dalamud/Utility/EventHandlerExtensions.cs b/Dalamud/Utility/EventHandlerExtensions.cs index 285e18fa2..415937dbf 100644 --- a/Dalamud/Utility/EventHandlerExtensions.cs +++ b/Dalamud/Utility/EventHandlerExtensions.cs @@ -4,6 +4,7 @@ using Dalamud.Game; using Dalamud.Game.Gui.ContextMenu; using Dalamud.Game.Gui.NamePlate; using Dalamud.Plugin.Services; + using Serilog; namespace Dalamud.Utility; diff --git a/Dalamud/Utility/FuzzyMatcher.cs b/Dalamud/Utility/FuzzyMatcher.cs index 03723da89..d8b881300 100644 --- a/Dalamud/Utility/FuzzyMatcher.cs +++ b/Dalamud/Utility/FuzzyMatcher.cs @@ -1,4 +1,4 @@ -#define BORDER_MATCHING +#define BORDER_MATCHING using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -32,18 +32,12 @@ internal readonly ref struct FuzzyMatcher this.needleFinalPosition = this.needleSpan.Length - 1; this.mode = matchMode; - switch (matchMode) + this.needleSegments = matchMode switch { - case MatchMode.FuzzyParts: - this.needleSegments = FindNeedleSegments(this.needleSpan); - break; - case MatchMode.Fuzzy: - case MatchMode.Simple: - this.needleSegments = EmptySegArray; - break; - default: - throw new ArgumentOutOfRangeException(nameof(matchMode), matchMode, null); - } + MatchMode.FuzzyParts => FindNeedleSegments(this.needleSpan), + MatchMode.Fuzzy or MatchMode.Simple => EmptySegArray, + _ => throw new ArgumentOutOfRangeException(nameof(matchMode), matchMode, null), + }; } private static (int Start, int End)[] FindNeedleSegments(ReadOnlySpan span) diff --git a/Dalamud/Utility/Hash.cs b/Dalamud/Utility/Hash.cs index 08fc78901..952c2305f 100644 --- a/Dalamud/Utility/Hash.cs +++ b/Dalamud/Utility/Hash.cs @@ -1,4 +1,4 @@ -using System.Security.Cryptography; +using System.Security.Cryptography; namespace Dalamud.Utility; @@ -24,10 +24,9 @@ public static class Hash /// The computed hash. internal static string GetSha256Hash(byte[] buffer) { - using var sha = SHA256.Create(); - var hash = sha.ComputeHash(buffer); + var hash = SHA256.HashData(buffer); return ByteArrayToString(hash); } - private static string ByteArrayToString(byte[] ba) => BitConverter.ToString(ba).Replace("-", string.Empty); + private static string ByteArrayToString(byte[] ba) => Convert.ToHexString(ba); } diff --git a/Dalamud/Utility/RollingList.cs b/Dalamud/Utility/RollingList.cs index 0f1553bf9..896b74fbf 100644 --- a/Dalamud/Utility/RollingList.cs +++ b/Dalamud/Utility/RollingList.cs @@ -40,7 +40,7 @@ namespace Dalamud.Utility { ThrowHelper.ThrowArgumentOutOfRangeExceptionIfLessThan(nameof(size), size, 0); this.size = size; - this.items = new(); + this.items = []; } /// Initializes a new instance of the class. diff --git a/Dalamud/Utility/Signatures/SignatureHelper.cs b/Dalamud/Utility/Signatures/SignatureHelper.cs index cdf601852..e1a4dafc2 100755 --- a/Dalamud/Utility/Signatures/SignatureHelper.cs +++ b/Dalamud/Utility/Signatures/SignatureHelper.cs @@ -5,8 +5,8 @@ using System.Runtime.InteropServices; using Dalamud.Game; using Dalamud.Hooking; -using Dalamud.Logging; using Dalamud.Utility.Signatures.Wrappers; + using Serilog; namespace Dalamud.Utility.Signatures; @@ -72,9 +72,8 @@ internal static class SignatureHelper } } - IntPtr ptr; var success = sig.ScanType == ScanType.Text - ? scanner.TryScanText(sig.Signature, out ptr) + ? scanner.TryScanText(sig.Signature, out var ptr) : scanner.TryGetStaticAddressFromSig(sig.Signature, out ptr); if (!success) { @@ -159,7 +158,7 @@ internal static class SignatureHelper continue; } - var hook = creator.Invoke(null, new object?[] { ptr, detour, false }) as IDalamudHook; + var hook = creator.Invoke(null, [ptr, detour, false]) as IDalamudHook; info.SetValue(self, hook); createdHooks.Add(hook); diff --git a/Dalamud/Utility/StringExtensions.cs b/Dalamud/Utility/StringExtensions.cs index c28aebab2..7f9975f82 100644 --- a/Dalamud/Utility/StringExtensions.cs +++ b/Dalamud/Utility/StringExtensions.cs @@ -57,7 +57,7 @@ public static class StringExtensions /// The input string. /// /// A new string with the first character converted to uppercase. - [return: NotNullIfNotNull("input")] + [return: NotNullIfNotNull(nameof(input))] public static string? FirstCharToUpper(this string? input, CultureInfo? culture = null) => string.IsNullOrWhiteSpace(input) ? input @@ -69,7 +69,7 @@ public static class StringExtensions /// The input string. /// /// A new string with the first character converted to lowercase. - [return: NotNullIfNotNull("input")] + [return: NotNullIfNotNull(nameof(input))] public static string? FirstCharToLower(this string? input, CultureInfo? culture = null) => string.IsNullOrWhiteSpace(input) ? input diff --git a/Dalamud/Utility/TerraFxCom/TerraFxComInterfaceExtensions.cs b/Dalamud/Utility/TerraFxCom/TerraFxComInterfaceExtensions.cs index ec108403e..f952cba7e 100644 --- a/Dalamud/Utility/TerraFxCom/TerraFxComInterfaceExtensions.cs +++ b/Dalamud/Utility/TerraFxCom/TerraFxComInterfaceExtensions.cs @@ -51,38 +51,22 @@ internal static unsafe partial class TerraFxComInterfaceExtensions throw new ArgumentOutOfRangeException(nameof(mode), mode, null); } - switch (access) + grfMode |= access switch { - case FileAccess.Read: - grfMode |= STGM.STGM_READ; - break; - case FileAccess.Write: - grfMode |= STGM.STGM_WRITE; - break; - case FileAccess.ReadWrite: - grfMode |= STGM.STGM_READWRITE; - break; - default: - throw new ArgumentOutOfRangeException(nameof(access), access, null); - } + FileAccess.Read => STGM.STGM_READ, + FileAccess.Write => STGM.STGM_WRITE, + FileAccess.ReadWrite => (uint)STGM.STGM_READWRITE, + _ => throw new ArgumentOutOfRangeException(nameof(access), access, null), + }; - switch (share) + grfMode |= share switch { - case FileShare.None: - grfMode |= STGM.STGM_SHARE_EXCLUSIVE; - break; - case FileShare.Read: - grfMode |= STGM.STGM_SHARE_DENY_WRITE; - break; - case FileShare.Write: - grfMode |= STGM.STGM_SHARE_DENY_READ; - break; - case FileShare.ReadWrite: - grfMode |= STGM.STGM_SHARE_DENY_NONE; - break; - default: - throw new NotSupportedException($"Only ${FileShare.Read} and ${FileShare.Write} are supported."); - } + FileShare.None => STGM.STGM_SHARE_EXCLUSIVE, + FileShare.Read => STGM.STGM_SHARE_DENY_WRITE, + FileShare.Write => STGM.STGM_SHARE_DENY_READ, + FileShare.ReadWrite => (uint)STGM.STGM_SHARE_DENY_NONE, + _ => throw new NotSupportedException($"Only ${FileShare.Read} and ${FileShare.Write} are supported."), + }; using var stream = default(ComPtr); fixed (char* pPath = path) diff --git a/Dalamud/Utility/Timing/Timings.cs b/Dalamud/Utility/Timing/Timings.cs index e2c00461c..563221fb9 100644 --- a/Dalamud/Utility/Timing/Timings.cs +++ b/Dalamud/Utility/Timing/Timings.cs @@ -19,12 +19,12 @@ public static class Timings /// /// All concluded timings. /// - internal static readonly SortedList AllTimings = new(); + internal static readonly SortedList AllTimings = []; /// /// List of all timing events. /// - internal static readonly List Events = new(); + internal static readonly List Events = []; private static readonly AsyncLocal>> TaskTimingHandleStorage = new(); @@ -36,7 +36,7 @@ public static class Timings get { if (TaskTimingHandleStorage.Value == null || TaskTimingHandleStorage.Value.Item1 != Task.CurrentId) - TaskTimingHandleStorage.Value = Tuple.Create>(Task.CurrentId, new()); + TaskTimingHandleStorage.Value = Tuple.Create>(Task.CurrentId, []); return TaskTimingHandleStorage.Value!.Item2!; } set => TaskTimingHandleStorage.Value = Tuple.Create(Task.CurrentId, value); @@ -53,7 +53,7 @@ public static class Timings var outerTimingHandle = TaskTimingHandles; return () => { - T res = default(T); + var res = default(T); var prev = TaskTimingHandles; TaskTimingHandles = outerTimingHandle; try diff --git a/Dalamud/Utility/Util.cs b/Dalamud/Utility/Util.cs index 0ea5bbcbf..72db5cfc6 100644 --- a/Dalamud/Utility/Util.cs +++ b/Dalamud/Utility/Util.cs @@ -367,7 +367,7 @@ public static partial class Util /// Human readable version. public static string FormatBytes(long bytes) { - string[] suffix = { "B", "KB", "MB", "GB", "TB" }; + string[] suffix = ["B", "KB", "MB", "GB", "TB"]; int i; double dblSByte = bytes; for (i = 0; i < suffix.Length && bytes >= 1024; i++, bytes /= 1024) @@ -823,7 +823,7 @@ public static partial class Util MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, null, - new[] { typeof(object), typeof(IList), typeof(ulong) }, + [typeof(object), typeof(IList), typeof(ulong)], obj.GetType(), true); @@ -850,7 +850,7 @@ public static partial class Util ilg.Emit(OpCodes.Call, mm); ilg.Emit(OpCodes.Ret); - dm.Invoke(null, new[] { obj, path, addr }); + dm.Invoke(null, [obj, path, addr]); } #pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type @@ -1029,8 +1029,8 @@ public static partial class Util foreach (var f in obj.GetType() .GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance)) { - var fixedBuffer = (FixedBufferAttribute)f.GetCustomAttribute(typeof(FixedBufferAttribute)); - var offset = (FieldOffsetAttribute)f.GetCustomAttribute(typeof(FieldOffsetAttribute)); + var fixedBuffer = f.GetCustomAttribute(); + var offset = f.GetCustomAttribute(); if (fixedBuffer != null) { diff --git a/Dalamud/Utility/WeakConcurrentCollection.cs b/Dalamud/Utility/WeakConcurrentCollection.cs index a3bc04651..c23ebac9a 100644 --- a/Dalamud/Utility/WeakConcurrentCollection.cs +++ b/Dalamud/Utility/WeakConcurrentCollection.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; @@ -11,7 +11,7 @@ namespace Dalamud.Utility; /// The type of object that we're tracking. public class WeakConcurrentCollection : ICollection where T : class { - private readonly ConditionalWeakTable cwt = new(); + private readonly ConditionalWeakTable cwt = []; /// public int Count => this.cwt.Count(); From 290ad9fc41aa784dd7be40f329dcdb13a8bc3aec Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Fri, 9 Jan 2026 10:48:58 +0100 Subject: [PATCH 41/99] Fix leaking colors in sheet redirects for Item --- Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs b/Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs index d16b3b9b3..58b9011e6 100644 --- a/Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs +++ b/Dalamud/Game/Text/Evaluator/SeStringEvaluator.cs @@ -845,7 +845,7 @@ internal class SeStringEvaluator : IServiceType, ISeStringEvaluator using var rssb = new RentedSeStringBuilder(); var sb = rssb.Builder; - sb.Append(this.EvaluateFromAddon(6, [rarity], context.Language)); + sb.Append(this.EvaluateFromAddon(6, [rarity], context.Language)); // appends colortype and edgecolortype if (!skipLink) sb.PushLink(LinkMacroPayloadType.Item, itemId, rarity, 0u); // arg3 = some LogMessage flag based on LogKind RowId? => "89 5C 24 20 E8 ?? ?? ?? ?? 48 8B 1F" @@ -868,6 +868,9 @@ internal class SeStringEvaluator : IServiceType, ISeStringEvaluator if (!skipLink) sb.PopLink(); + sb.PopEdgeColorType(); + sb.PopColorType(); + text = sb.ToReadOnlySeString(); } From 90c29e5646364106ee14fa58b0fbca6452c098ae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 9 Jan 2026 18:40:18 +0000 Subject: [PATCH 42/99] Update Excel Schema --- lib/Lumina.Excel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Lumina.Excel b/lib/Lumina.Excel index 52cb5e0a9..31e50c3f2 160000 --- a/lib/Lumina.Excel +++ b/lib/Lumina.Excel @@ -1 +1 @@ -Subproject commit 52cb5e0a9a7a1138d8c2406c277307a6c9ad8898 +Subproject commit 31e50c3f267dd845891b328140106a0cc3b1f35e From b29b7851d99ac09d3672f7d473656b33ad76f820 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 9 Jan 2026 18:40:20 +0000 Subject: [PATCH 43/99] Update ClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index b6f886afc..ae1917bf1 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit b6f886afc2b1a54d8fd76c37a260a05f214a559e +Subproject commit ae1917bf103926bfd157c7d911efac58c0e28666 From f635673ce91e33412a3ed1bcc477567906787940 Mon Sep 17 00:00:00 2001 From: MidoriKami Date: Fri, 9 Jan 2026 12:51:08 -0800 Subject: [PATCH 44/99] Use AgentInterfacePtr --- Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs b/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs index b4a904dde..ef0f9021a 100644 --- a/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs +++ b/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs @@ -1,4 +1,6 @@ -namespace Dalamud.Game.Agent.AgentArgTypes; +using Dalamud.Game.NativeWrapper; + +namespace Dalamud.Game.Agent.AgentArgTypes; /// /// Base class for AgentLifecycle AgentArgTypes. @@ -15,7 +17,7 @@ public unsafe class AgentArgs /// /// Gets the pointer to the Agents AgentInterface*. /// - public nint Agent { get; internal set; } + public AgentInterfacePtr Agent { get; internal set; } /// /// Gets the agent id. @@ -33,5 +35,5 @@ public unsafe class AgentArgs /// AgentInterface. /// Typed pointer to contained Agents AgentInterface. public T* GetAgentPointer() where T : unmanaged - => (T*)this.Agent; + => (T*)this.Agent.Address; } From 6c8b2b4a6d4b10791e388a568f5bd11fec530c2f Mon Sep 17 00:00:00 2001 From: MidoriKami Date: Fri, 9 Jan 2026 12:52:33 -0800 Subject: [PATCH 45/99] Remove casts --- Dalamud/Game/Agent/AgentVirtualTable.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Dalamud/Game/Agent/AgentVirtualTable.cs b/Dalamud/Game/Agent/AgentVirtualTable.cs index 3c23616e8..e00f9e433 100644 --- a/Dalamud/Game/Agent/AgentVirtualTable.cs +++ b/Dalamud/Game/Agent/AgentVirtualTable.cs @@ -125,7 +125,7 @@ internal unsafe class AgentVirtualTable : IDisposable { this.LogEvent(EnableLogging); - this.receiveEventArgs.Agent = (nint)thisPtr; + this.receiveEventArgs.Agent = thisPtr; this.receiveEventArgs.AgentId = this.agentId; this.receiveEventArgs.ReturnValue = (nint)returnValue; this.receiveEventArgs.AtkValues = (nint)values; @@ -166,7 +166,7 @@ internal unsafe class AgentVirtualTable : IDisposable { this.LogEvent(EnableLogging); - this.filteredReceiveEventArgs.Agent = (nint)thisPtr; + this.filteredReceiveEventArgs.Agent = thisPtr; this.filteredReceiveEventArgs.AgentId = this.agentId; this.filteredReceiveEventArgs.ReturnValue = (nint)returnValue; this.filteredReceiveEventArgs.AtkValues = (nint)values; @@ -205,7 +205,7 @@ internal unsafe class AgentVirtualTable : IDisposable { this.LogEvent(EnableLogging); - this.showArgs.Agent = (nint)thisPtr; + this.showArgs.Agent = thisPtr; this.showArgs.AgentId = this.agentId; this.lifecycleService.InvokeListenersSafely(AgentEvent.PreShow, this.showArgs); @@ -233,7 +233,7 @@ internal unsafe class AgentVirtualTable : IDisposable { this.LogEvent(EnableLogging); - this.hideArgs.Agent = (nint)thisPtr; + this.hideArgs.Agent = thisPtr; this.hideArgs.AgentId = this.agentId; this.lifecycleService.InvokeListenersSafely(AgentEvent.PreHide, this.hideArgs); @@ -261,7 +261,7 @@ internal unsafe class AgentVirtualTable : IDisposable { this.LogEvent(EnableLogging); - this.updateArgs.Agent = (nint)thisPtr; + this.updateArgs.Agent = thisPtr; this.updateArgs.AgentId = this.agentId; this.lifecycleService.InvokeListenersSafely(AgentEvent.PreUpdate, this.updateArgs); @@ -289,7 +289,7 @@ internal unsafe class AgentVirtualTable : IDisposable { this.LogEvent(EnableLogging); - this.gameEventArgs.Agent = (nint)thisPtr; + this.gameEventArgs.Agent = thisPtr; this.gameEventArgs.AgentId = this.agentId; this.gameEventArgs.GameEvent = (int)gameEvent; @@ -320,7 +320,7 @@ internal unsafe class AgentVirtualTable : IDisposable { this.LogEvent(EnableLogging); - this.levelChangeArgs.Agent = (nint)thisPtr; + this.levelChangeArgs.Agent = thisPtr; this.levelChangeArgs.AgentId = this.agentId; this.levelChangeArgs.ClassJobId = classJobId; this.levelChangeArgs.Level = level; @@ -353,7 +353,7 @@ internal unsafe class AgentVirtualTable : IDisposable { this.LogEvent(EnableLogging); - this.classJobChangeArgs.Agent = (nint)thisPtr; + this.classJobChangeArgs.Agent = thisPtr; this.classJobChangeArgs.AgentId = this.agentId; this.classJobChangeArgs.ClassJobId = classJobId; From b2fb6949d2b9bafefcd35c1ac7dcbb9d7321539c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 10 Jan 2026 06:37:41 +0000 Subject: [PATCH 46/99] Update ClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index ae1917bf1..d83e0c13d 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit ae1917bf103926bfd157c7d911efac58c0e28666 +Subproject commit d83e0c13d3c802d4a483f373edcd129bc4802073 From fab7eef244e17a66c57caf1131709f501cf3c7f7 Mon Sep 17 00:00:00 2001 From: Infi Date: Sat, 10 Jan 2026 14:25:22 +0100 Subject: [PATCH 47/99] Update UIColorWidget.cs --- Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs index 9baf2848a..dc1ab4e30 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Text; using Dalamud.Bindings.ImGui; +using Dalamud.Interface.Utility.Raii; using Dalamud.Data; using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification.Internal; From 8bb6cdd8d6a0e524cb2355f22ba1001d5f176139 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 10 Jan 2026 16:57:18 +0100 Subject: [PATCH 48/99] Add "enum cloning" source generator --- Dalamud.sln | 23 +++ Dalamud/Dalamud.csproj | 9 + Dalamud/EnumCloneMap.txt | 3 + .../Dalamud.EnumGenerator.Sample.csproj | 20 ++ .../EnumCloneMap.txt | 4 + .../SourceEnums.cs | 9 + .../Dalamud.EnumGenerator.Tests.csproj | 29 +++ .../EnumCloneMapTests.cs | 47 +++++ .../Utils/TestAdditionalFile.cs | 21 ++ .../AnalyzerReleases.Shipped.md | 3 + .../AnalyzerReleases.Unshipped.md | 9 + .../Dalamud.EnumGenerator.csproj | 33 ++++ .../EnumCloneGenerator.cs | 181 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 4 + 14 files changed, 395 insertions(+) create mode 100644 Dalamud/EnumCloneMap.txt create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/Dalamud.EnumGenerator.Sample.csproj create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/EnumCloneMap.txt create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/SourceEnums.cs create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/Dalamud.EnumGenerator.Tests.csproj create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/EnumCloneMapTests.cs create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/Utils/TestAdditionalFile.cs create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/AnalyzerReleases.Shipped.md create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/AnalyzerReleases.Unshipped.md create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/Dalamud.EnumGenerator.csproj create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/EnumCloneGenerator.cs create mode 100644 generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/Properties/AssemblyInfo.cs diff --git a/Dalamud.sln b/Dalamud.sln index de91e7ceb..fa26a5d67 100644 --- a/Dalamud.sln +++ b/Dalamud.sln @@ -75,6 +75,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lumina.Excel.Generator", "l EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lumina.Excel", "lib\Lumina.Excel\src\Lumina.Excel\Lumina.Excel.csproj", "{88FB719B-EB41-73C5-8D25-C03E0C69904F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source Generators", "Source Generators", "{50BEC23B-FFFD-427B-A95D-27E1D1958FFF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.EnumGenerator", "generators\Dalamud.EnumGenerator\Dalamud.EnumGenerator\Dalamud.EnumGenerator.csproj", "{27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.EnumGenerator.Sample", "generators\Dalamud.EnumGenerator\Dalamud.EnumGenerator.Sample\Dalamud.EnumGenerator.Sample.csproj", "{8CDAEB2D-5022-450A-A97F-181C6270185F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.EnumGenerator.Tests", "generators\Dalamud.EnumGenerator\Dalamud.EnumGenerator.Tests\Dalamud.EnumGenerator.Tests.csproj", "{F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -173,6 +181,18 @@ Global {88FB719B-EB41-73C5-8D25-C03E0C69904F}.Debug|Any CPU.Build.0 = Debug|Any CPU {88FB719B-EB41-73C5-8D25-C03E0C69904F}.Release|Any CPU.ActiveCfg = Release|Any CPU {88FB719B-EB41-73C5-8D25-C03E0C69904F}.Release|Any CPU.Build.0 = Release|Any CPU + {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Debug|Any CPU.ActiveCfg = Debug|x64 + {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Debug|Any CPU.Build.0 = Debug|x64 + {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Release|Any CPU.ActiveCfg = Release|x64 + {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Release|Any CPU.Build.0 = Release|x64 + {8CDAEB2D-5022-450A-A97F-181C6270185F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {8CDAEB2D-5022-450A-A97F-181C6270185F}.Debug|Any CPU.Build.0 = Debug|x64 + {8CDAEB2D-5022-450A-A97F-181C6270185F}.Release|Any CPU.ActiveCfg = Release|x64 + {8CDAEB2D-5022-450A-A97F-181C6270185F}.Release|Any CPU.Build.0 = Release|x64 + {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Debug|Any CPU.ActiveCfg = Debug|x64 + {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Debug|Any CPU.Build.0 = Debug|x64 + {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Release|Any CPU.ActiveCfg = Release|x64 + {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Release|Any CPU.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -197,6 +217,9 @@ Global {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {E15BDA6D-E881-4482-94BA-BE5527E917FF} {5A44DF0C-C9DA-940F-4D6B-4A11D13AEA3D} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {88FB719B-EB41-73C5-8D25-C03E0C69904F} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8} = {50BEC23B-FFFD-427B-A95D-27E1D1958FFF} + {8CDAEB2D-5022-450A-A97F-181C6270185F} = {50BEC23B-FFFD-427B-A95D-27E1D1958FFF} + {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6} = {50BEC23B-FFFD-427B-A95D-27E1D1958FFF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {79B65AC9-C940-410E-AB61-7EA7E12C7599} diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index f5e75af63..bb8f5af7c 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -88,6 +88,15 @@ + + + + + + + + + imgui-frag.hlsl.bytes diff --git a/Dalamud/EnumCloneMap.txt b/Dalamud/EnumCloneMap.txt new file mode 100644 index 000000000..bbc3c1eda --- /dev/null +++ b/Dalamud/EnumCloneMap.txt @@ -0,0 +1,3 @@ +# Format: Target.Full.TypeName = Source.Full.EnumTypeName +# Example: Generate a local enum MyGeneratedEnum in namespace Sample.Gen mapped to SourceEnums.SampleSourceEnum +Dalamud.Game.Agent.AgentId = FFXIVClientStructs.FFXIV.Client.UI.Agent.AgentId diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/Dalamud.EnumGenerator.Sample.csproj b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/Dalamud.EnumGenerator.Sample.csproj new file mode 100644 index 000000000..225ea5f94 --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/Dalamud.EnumGenerator.Sample.csproj @@ -0,0 +1,20 @@ + + + + net9.0 + enable + Dalamud.EnumGenerator.Sample + + false + + + + + + + + + + + + diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/EnumCloneMap.txt b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/EnumCloneMap.txt new file mode 100644 index 000000000..a7db08bf3 --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/EnumCloneMap.txt @@ -0,0 +1,4 @@ +# Format: Target.Full.TypeName = Source.Full.EnumTypeName +# Example: Generate a local enum MyGeneratedEnum in namespace Sample.Gen mapped to SourceEnums.SampleSourceEnum +Dalamud.EnumGenerator.Sample.Gen.MyGeneratedEnum = Dalamud.EnumGenerator.Sample.SourceEnums.SampleSourceEnum + diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/SourceEnums.cs b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/SourceEnums.cs new file mode 100644 index 000000000..407b4c151 --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Sample/SourceEnums.cs @@ -0,0 +1,9 @@ +namespace Dalamud.EnumGenerator.Sample.SourceEnums +{ + public enum SampleSourceEnum : long + { + First = 1, + Second = 2, + Third = 10000000000L + } +} diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/Dalamud.EnumGenerator.Tests.csproj b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/Dalamud.EnumGenerator.Tests.csproj new file mode 100644 index 000000000..50de4a7c8 --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/Dalamud.EnumGenerator.Tests.csproj @@ -0,0 +1,29 @@ + + + + net9.0 + enable + + false + + Dalamud.EnumGenerator.Tests + + false + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/EnumCloneMapTests.cs b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/EnumCloneMapTests.cs new file mode 100644 index 000000000..f14279c53 --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/EnumCloneMapTests.cs @@ -0,0 +1,47 @@ +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Xunit; + +namespace Dalamud.EnumGenerator.Tests; + +public class EnumCloneMapTests +{ + [Fact] + public void ParseMappings_SimpleLines_ParsesCorrectly() + { + var text = @"# Comment line +My.Namespace.Target = Other.Namespace.Source + +Another.Target = Some.Source"; + + var results = Dalamud.EnumGenerator.EnumCloneGenerator.ParseMappings(text); + + Assert.Equal(2, results.Length); + Assert.Equal("My.Namespace.Target", results[0].TargetFullName); + Assert.Equal("Other.Namespace.Source", results[0].SourceFullName); + Assert.Equal("Another.Target", results[1].TargetFullName); + } + + [Fact] + public void Generator_ProducesFile_WhenSourceResolved() + { + // We'll create a compilation that contains a source enum type and add an AdditionalText mapping + var sourceEnum = @"namespace Foo.Bar { public enum SourceEnum { A = 1, B = 2 } }"; + + var mapText = "GeneratedNs.TargetEnum = Foo.Bar.SourceEnum"; + + var generator = new EnumCloneGenerator(); + var driver = CSharpGeneratorDriver.Create(generator) + .AddAdditionalTexts(ImmutableArray.Create(new Utils.TestAdditionalFile("EnumCloneMap.txt", mapText))); + + var compilation = CSharpCompilation.Create("TestGen", [CSharpSyntaxTree.ParseText(sourceEnum)], + [MetadataReference.CreateFromFile(typeof(object).Assembly.Location)]); + + driver.RunGeneratorsAndUpdateCompilation(compilation, out var newCompilation, out var diagnostics); + + var generated = newCompilation.SyntaxTrees.Select(t => t.FilePath).Where(p => p.EndsWith("TargetEnum.CloneEnum.g.cs")).ToArray(); + Assert.Single(generated); + } +} diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/Utils/TestAdditionalFile.cs b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/Utils/TestAdditionalFile.cs new file mode 100644 index 000000000..e5c0df848 --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator.Tests/Utils/TestAdditionalFile.cs @@ -0,0 +1,21 @@ +using System.Threading; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; + +namespace Dalamud.EnumGenerator.Tests.Utils; + +public class TestAdditionalFile : AdditionalText +{ + private readonly SourceText text; + + public TestAdditionalFile(string path, string text) + { + Path = path; + this.text = SourceText.From(text); + } + + public override SourceText GetText(CancellationToken cancellationToken = new()) => this.text; + + public override string Path { get; } +} diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/AnalyzerReleases.Shipped.md b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/AnalyzerReleases.Shipped.md new file mode 100644 index 000000000..60b59dd99 --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/AnalyzerReleases.Shipped.md @@ -0,0 +1,3 @@ +; Shipped analyzer releases +; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/AnalyzerReleases.Unshipped.md b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/AnalyzerReleases.Unshipped.md new file mode 100644 index 000000000..e90084796 --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/AnalyzerReleases.Unshipped.md @@ -0,0 +1,9 @@ +; Unshipped analyzer release +; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + +### New Rules + +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +ENUMGEN001 | EnumGenerator | Warning | SourceGeneratorWithAttributes +ENUMGEN002 | EnumGenerator | Warning | SourceGeneratorWithAttributes \ No newline at end of file diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/Dalamud.EnumGenerator.csproj b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/Dalamud.EnumGenerator.csproj new file mode 100644 index 000000000..106b036a8 --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/Dalamud.EnumGenerator.csproj @@ -0,0 +1,33 @@ + + + + netstandard2.0 + false + enable + latest + + true + true + + Dalamud.EnumGenerator + Dalamud.EnumGenerator + + false + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/EnumCloneGenerator.cs b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/EnumCloneGenerator.cs new file mode 100644 index 000000000..95af4c38b --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/EnumCloneGenerator.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Text; +using System.Globalization; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; + +namespace Dalamud.EnumGenerator; + +[Generator] +public class EnumCloneGenerator : IIncrementalGenerator +{ + private const string NewLine = "\r\n"; + + private const string MappingFileName = "EnumCloneMap.txt"; + + private static readonly DiagnosticDescriptor MissingSourceDescriptor = new( + id: "ENUMGEN001", + title: "Source enum not found", + messageFormat: "Source enum '{0}' could not be resolved by the compilation", + category: "EnumGenerator", + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + private static readonly DiagnosticDescriptor DuplicateTargetDescriptor = new( + id: "ENUMGEN002", + title: "Duplicate target mapping", + messageFormat: "Target enum '{0}' is mapped multiple times; generation skipped for this target", + category: "EnumGenerator", + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + // Read mappings from additional files named EnumCloneMap.txt + var mappingEntries = context.AdditionalTextsProvider + .Where(at => Path.GetFileName(at.Path).Equals(MappingFileName, StringComparison.OrdinalIgnoreCase)) + .SelectMany((at, _) => ParseMappings(at.GetText()?.ToString() ?? string.Empty)); + + // Combine with compilation so we can resolve types + var compilationAndMaps = context.CompilationProvider.Combine(mappingEntries.Collect()); + + context.RegisterSourceOutput(compilationAndMaps, (spc, pair) => + { + var compilation = pair.Left; + var maps = pair.Right; + + // Detect duplicate targets first and report diagnostics + var duplicateTargets = maps.GroupBy(m => m.TargetFullName, StringComparer.OrdinalIgnoreCase) + .Where(g => g.Count() > 1) + .Select(g => g.Key) + .ToImmutableArray(); + foreach (var dup in duplicateTargets) + { + var diag = Diagnostic.Create(DuplicateTargetDescriptor, Location.None, dup); + spc.ReportDiagnostic(diag); + } + + foreach (var (targetFullName, sourceFullName) in maps) + { + if (string.IsNullOrWhiteSpace(targetFullName) || string.IsNullOrWhiteSpace(sourceFullName)) + continue; + + if (duplicateTargets.Contains(targetFullName, StringComparer.OrdinalIgnoreCase)) + continue; + + // Resolve the source enum type by metadata name (namespace.type) + var sourceSymbol = compilation.GetTypeByMetadataName(sourceFullName); + if (sourceSymbol is null) + { + // Report diagnostic for missing source type + var diag = Diagnostic.Create(MissingSourceDescriptor, Location.None, sourceFullName); + spc.ReportDiagnostic(diag); + continue; + } + + if (sourceSymbol.TypeKind != TypeKind.Enum) + continue; + + var sourceNamed = sourceSymbol; // GetTypeByMetadataName already returns INamedTypeSymbol + + // Split target into namespace and type name + string? targetNamespace = null; + var targetName = targetFullName; + var lastDot = targetFullName.LastIndexOf('.'); + if (lastDot >= 0) + { + targetNamespace = targetFullName.Substring(0, lastDot); + targetName = targetFullName.Substring(lastDot + 1); + } + + var underlyingType = sourceNamed.EnumUnderlyingType; + var underlyingDisplay = underlyingType?.ToDisplayString() ?? "int"; + + var fields = sourceNamed.GetMembers() + .OfType() + .Where(f => f.IsStatic && f.HasConstantValue) + .ToArray(); + + var memberLines = fields.Select(f => + { + var name = f.Name; + var constValue = f.ConstantValue; + string literal; + + var st = underlyingType?.SpecialType ?? SpecialType.System_Int32; + + if (constValue is null) + { + literal = "0"; + } + else if (st == SpecialType.System_UInt64) + { + literal = Convert.ToString(constValue, CultureInfo.InvariantCulture) + "UL"; + } + else if (st == SpecialType.System_UInt32) + { + literal = Convert.ToString(constValue, CultureInfo.InvariantCulture) + "U"; + } + else if (st == SpecialType.System_Int64) + { + literal = Convert.ToString(constValue, CultureInfo.InvariantCulture) + "L"; + } + else + { + literal = Convert.ToString(constValue, CultureInfo.InvariantCulture) ?? throw new InvalidOperationException("Unable to convert enum constant value to string."); + } + + return $" {name} = {literal},"; + }); + + var membersText = string.Join(NewLine, memberLines); + + var nsPrefix = targetNamespace is null ? string.Empty : $"namespace {targetNamespace};" + NewLine + NewLine; + + var code = "// " + NewLine + NewLine + + nsPrefix + + $"public enum {targetName} : {underlyingDisplay}" + NewLine + + "{" + NewLine + + membersText + NewLine + + "}" + NewLine; + + var hintName = $"{targetName}.CloneEnum.g.cs"; + spc.AddSource(hintName, SourceText.From(code, Encoding.UTF8)); + } + }); + } + + internal static ImmutableArray<(string TargetFullName, string SourceFullName)> ParseMappings(string text) + { + var builder = ImmutableArray.CreateBuilder<(string, string)>(); + using var reader = new StringReader(text); + string? line; + while ((line = reader.ReadLine()) != null) + { + // Remove comments starting with # + var commentIndex = line.IndexOf('#'); + var content = commentIndex >= 0 ? line.Substring(0, commentIndex) : line; + content = content.Trim(); + if (string.IsNullOrEmpty(content)) + continue; + + // Expected format: Target.Full.Name = Source.Full.Name + var idx = content.IndexOf('='); + if (idx <= 0) + continue; + + var left = content.Substring(0, idx).Trim(); + var right = content.Substring(idx + 1).Trim(); + if (string.IsNullOrEmpty(left) || string.IsNullOrEmpty(right)) + continue; + + builder.Add((left, right)); + } + + return builder.ToImmutable(); + } +} diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/Properties/AssemblyInfo.cs b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..6eac4d12e --- /dev/null +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/Properties/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Dalamud.EnumGenerator.Tests")] + From dd94d107225e6fa0d652d52a813383c394c09cea Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 10 Jan 2026 17:09:51 +0100 Subject: [PATCH 49/99] Add conversion extension method from source enum --- .../Dalamud.EnumGenerator/EnumCloneGenerator.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/EnumCloneGenerator.cs b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/EnumCloneGenerator.cs index 95af4c38b..10cf0723c 100644 --- a/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/EnumCloneGenerator.cs +++ b/generators/Dalamud.EnumGenerator/Dalamud.EnumGenerator/EnumCloneGenerator.cs @@ -136,12 +136,24 @@ public class EnumCloneGenerator : IIncrementalGenerator var nsPrefix = targetNamespace is null ? string.Empty : $"namespace {targetNamespace};" + NewLine + NewLine; + var sourceFullyQualified = sourceNamed.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + var code = "// " + NewLine + NewLine + nsPrefix + $"public enum {targetName} : {underlyingDisplay}" + NewLine + "{" + NewLine + membersText + NewLine - + "}" + NewLine; + + "}" + NewLine + NewLine; + + var extClassName = targetName + "Conversions"; + var extMethodName = "ToDalamud" + targetName; + + var extClass = $"public static class {extClassName}" + NewLine + + "{" + NewLine + + $" public static {targetName} {extMethodName}(this {sourceFullyQualified} value) => ({targetName})(({underlyingDisplay})value);" + NewLine + + "}" + NewLine; + + code += extClass; var hintName = $"{targetName}.CloneEnum.g.cs"; spc.AddSource(hintName, SourceText.From(code, Encoding.UTF8)); From 0c2ce097ed2243b304f06207d9cc9692be43de0c Mon Sep 17 00:00:00 2001 From: MidoriKami Date: Sat, 10 Jan 2026 08:30:15 -0800 Subject: [PATCH 50/99] Use generated AgentId --- Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs | 2 +- Dalamud/Game/Agent/AgentLifecycle.cs | 20 +++++++++---------- .../Game/Agent/AgentLifecycleEventListener.cs | 4 ++-- Dalamud/Game/Agent/AgentVirtualTable.cs | 10 +++++----- Dalamud/Plugin/Services/IAgentLifecycle.cs | 8 ++++---- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs b/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs index ef0f9021a..1de80694f 100644 --- a/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs +++ b/Dalamud/Game/Agent/AgentArgTypes/AgentArgs.cs @@ -22,7 +22,7 @@ public unsafe class AgentArgs /// /// Gets the agent id. /// - public uint AgentId { get; internal set; } + public AgentId AgentId { get; internal set; } /// /// Gets the type of these args. diff --git a/Dalamud/Game/Agent/AgentLifecycle.cs b/Dalamud/Game/Agent/AgentLifecycle.cs index 1306a92c1..75ed47d86 100644 --- a/Dalamud/Game/Agent/AgentLifecycle.cs +++ b/Dalamud/Game/Agent/AgentLifecycle.cs @@ -57,7 +57,7 @@ internal unsafe class AgentLifecycle : IInternalDisposableService /// Gets a list of all AgentLifecycle Event Listeners. ///
/// Mapping is: EventType -> ListenerList - internal Dictionary>> EventListeners { get; } = []; + internal Dictionary>> EventListeners { get; } = []; /// void IInternalDisposableService.DisposeService() @@ -128,7 +128,7 @@ internal unsafe class AgentLifecycle : IInternalDisposableService if (!this.EventListeners.TryGetValue(eventType, out var agentListeners)) return; // Handle listeners for this event type that don't care which agent is triggering it - if (agentListeners.TryGetValue(uint.MaxValue, out var globalListeners)) + if (agentListeners.TryGetValue((AgentId)uint.MaxValue, out var globalListeners)) { foreach (var listener in globalListeners) { @@ -154,7 +154,7 @@ internal unsafe class AgentLifecycle : IInternalDisposableService } catch (Exception e) { - Log.Error(e, $"Exception in {blame} during {eventType} invoke, for specific agent {(AgentId)args.AgentId}."); + Log.Error(e, $"Exception in {blame} during {eventType} invoke, for specific agent {args.AgentId}."); } } } @@ -208,7 +208,7 @@ internal unsafe class AgentLifecycle : IInternalDisposableService } // AgentVirtualTable class handles creating the virtual table, and overriding each of the tracked virtual functions - AllocatedTables.Add(new AgentVirtualTable(agentPointer->Value, index, this)); + AllocatedTables.Add(new AgentVirtualTable(agentPointer->Value, (AgentId)index, this)); } catch (Exception e) { @@ -243,7 +243,7 @@ internal class AgentLifecyclePluginScoped : IInternalDisposableService, IAgentLi } /// - public void RegisterListener(AgentEvent eventType, IEnumerable agentIds, IAgentLifecycle.AgentEventDelegate handler) + public void RegisterListener(AgentEvent eventType, IEnumerable agentIds, IAgentLifecycle.AgentEventDelegate handler) { foreach (var agentId in agentIds) { @@ -252,7 +252,7 @@ internal class AgentLifecyclePluginScoped : IInternalDisposableService, IAgentLi } /// - public void RegisterListener(AgentEvent eventType, uint agentId, IAgentLifecycle.AgentEventDelegate handler) + public void RegisterListener(AgentEvent eventType, AgentId agentId, IAgentLifecycle.AgentEventDelegate handler) { var listener = new AgentLifecycleEventListener(eventType, agentId, handler); this.eventListeners.Add(listener); @@ -262,11 +262,11 @@ internal class AgentLifecyclePluginScoped : IInternalDisposableService, IAgentLi /// public void RegisterListener(AgentEvent eventType, IAgentLifecycle.AgentEventDelegate handler) { - this.RegisterListener(eventType, uint.MaxValue, handler); + this.RegisterListener(eventType, (AgentId)uint.MaxValue, handler); } /// - public void UnregisterListener(AgentEvent eventType, IEnumerable agentIds, IAgentLifecycle.AgentEventDelegate? handler = null) + public void UnregisterListener(AgentEvent eventType, IEnumerable agentIds, IAgentLifecycle.AgentEventDelegate? handler = null) { foreach (var agentId in agentIds) { @@ -275,7 +275,7 @@ internal class AgentLifecyclePluginScoped : IInternalDisposableService, IAgentLi } /// - public void UnregisterListener(AgentEvent eventType, uint agentId, IAgentLifecycle.AgentEventDelegate? handler = null) + public void UnregisterListener(AgentEvent eventType, AgentId agentId, IAgentLifecycle.AgentEventDelegate? handler = null) { this.eventListeners.RemoveAll(entry => { @@ -291,7 +291,7 @@ internal class AgentLifecyclePluginScoped : IInternalDisposableService, IAgentLi /// public void UnregisterListener(AgentEvent eventType, IAgentLifecycle.AgentEventDelegate? handler = null) { - this.UnregisterListener(eventType, uint.MaxValue, handler); + this.UnregisterListener(eventType, (AgentId)uint.MaxValue, handler); } /// diff --git a/Dalamud/Game/Agent/AgentLifecycleEventListener.cs b/Dalamud/Game/Agent/AgentLifecycleEventListener.cs index 3521d2c13..91f8aa3d3 100644 --- a/Dalamud/Game/Agent/AgentLifecycleEventListener.cs +++ b/Dalamud/Game/Agent/AgentLifecycleEventListener.cs @@ -13,7 +13,7 @@ public class AgentLifecycleEventListener /// Event type to listen for. /// Agent id to listen for. /// Delegate to invoke. - internal AgentLifecycleEventListener(AgentEvent eventType, uint agentId, IAgentLifecycle.AgentEventDelegate functionDelegate) + internal AgentLifecycleEventListener(AgentEvent eventType, AgentId agentId, IAgentLifecycle.AgentEventDelegate functionDelegate) { this.EventType = eventType; this.AgentId = agentId; @@ -24,7 +24,7 @@ public class AgentLifecycleEventListener /// Gets the agentId of the agent this listener is looking for. /// uint.MaxValue if it wants to be called for any agent. ///
- public uint AgentId { get; init; } + public AgentId AgentId { get; init; } /// /// Gets the event type this listener is looking for. diff --git a/Dalamud/Game/Agent/AgentVirtualTable.cs b/Dalamud/Game/Agent/AgentVirtualTable.cs index e00f9e433..e7f9a2f6e 100644 --- a/Dalamud/Game/Agent/AgentVirtualTable.cs +++ b/Dalamud/Game/Agent/AgentVirtualTable.cs @@ -27,7 +27,7 @@ internal unsafe class AgentVirtualTable : IDisposable private readonly AgentLifecycle lifecycleService; - private readonly uint agentId; + private readonly AgentId agentId; // Each agent gets its own set of args that are used to mutate the original call when used in pre-calls private readonly AgentReceiveEventArgs receiveEventArgs = new(); @@ -58,9 +58,9 @@ internal unsafe class AgentVirtualTable : IDisposable /// AgentInterface* for the agent to replace the table of. /// Agent ID. /// Reference to AgentLifecycle service to callback and invoke listeners. - internal AgentVirtualTable(AgentInterface* agent, uint agentId, AgentLifecycle lifecycleService) + internal AgentVirtualTable(AgentInterface* agent, AgentId agentId, AgentLifecycle lifecycleService) { - Log.Debug($"Initializing AgentVirtualTable for {(AgentId)agentId}, Address: {(nint)agent:X}"); + Log.Debug($"Initializing AgentVirtualTable for {agentId}, Address: {(nint)agent:X}"); this.agentInterface = agent; this.agentId = agentId; @@ -384,10 +384,10 @@ internal unsafe class AgentVirtualTable : IDisposable if (loggingEnabled) { // Manually disable the really spammy log events, you can comment this out if you need to debug them. - if (caller is "OnAgentUpdate" || (AgentId)this.agentId is AgentId.PadMouseMode) + if (caller is "OnAgentUpdate" || this.agentId is AgentId.PadMouseMode) return; - Log.Debug($"[{caller}]: {(AgentId)this.agentId}"); + Log.Debug($"[{caller}]: {this.agentId}"); } } } diff --git a/Dalamud/Plugin/Services/IAgentLifecycle.cs b/Dalamud/Plugin/Services/IAgentLifecycle.cs index a1ed26125..62178408d 100644 --- a/Dalamud/Plugin/Services/IAgentLifecycle.cs +++ b/Dalamud/Plugin/Services/IAgentLifecycle.cs @@ -24,7 +24,7 @@ public interface IAgentLifecycle : IDalamudService /// Event type to trigger on. /// Agent IDs that will trigger the handler to be invoked. /// The handler to invoke. - void RegisterListener(AgentEvent eventType, IEnumerable agentIds, AgentEventDelegate handler); + void RegisterListener(AgentEvent eventType, IEnumerable agentIds, AgentEventDelegate handler); /// /// Register a listener that will trigger on the specified event only for the specified agent. @@ -32,7 +32,7 @@ public interface IAgentLifecycle : IDalamudService /// Event type to trigger on. /// The agent ID that will trigger the handler to be invoked. /// The handler to invoke. - void RegisterListener(AgentEvent eventType, uint agentId, AgentEventDelegate handler); + void RegisterListener(AgentEvent eventType, AgentId agentId, AgentEventDelegate handler); /// /// Register a listener that will trigger on the specified event for any agent. @@ -50,7 +50,7 @@ public interface IAgentLifecycle : IDalamudService /// Event type to deregister. /// Agent IDs to deregister. /// Optional specific handler to remove. - void UnregisterListener(AgentEvent eventType, IEnumerable agentIds, [Optional] AgentEventDelegate handler); + void UnregisterListener(AgentEvent eventType, IEnumerable agentIds, [Optional] AgentEventDelegate handler); /// /// Unregister all listeners for the specified event type and agent ID. @@ -61,7 +61,7 @@ public interface IAgentLifecycle : IDalamudService /// Event type to deregister. /// Agent id to deregister. /// Optional specific handler to remove. - void UnregisterListener(AgentEvent eventType, uint agentId, [Optional] AgentEventDelegate handler); + void UnregisterListener(AgentEvent eventType, AgentId agentId, [Optional] AgentEventDelegate handler); /// /// Unregister an event type handler.
This will only remove a handler that is added via . From c545205e66d6e1baaa17083d414dbffa4a7f76c6 Mon Sep 17 00:00:00 2001 From: goaaats Date: Sat, 10 Jan 2026 17:53:49 +0100 Subject: [PATCH 51/99] Remove analyzer for source generator projects --- Dalamud.sln | 3 +++ generators/Directory.Build.props | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 generators/Directory.Build.props diff --git a/Dalamud.sln b/Dalamud.sln index fa26a5d67..3b1c4fd91 100644 --- a/Dalamud.sln +++ b/Dalamud.sln @@ -76,6 +76,9 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lumina.Excel", "lib\Lumina.Excel\src\Lumina.Excel\Lumina.Excel.csproj", "{88FB719B-EB41-73C5-8D25-C03E0C69904F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source Generators", "Source Generators", "{50BEC23B-FFFD-427B-A95D-27E1D1958FFF}" + ProjectSection(SolutionItems) = preProject + generators\Directory.Build.props = generators\Directory.Build.props + EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dalamud.EnumGenerator", "generators\Dalamud.EnumGenerator\Dalamud.EnumGenerator\Dalamud.EnumGenerator.csproj", "{27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}" EndProject diff --git a/generators/Directory.Build.props b/generators/Directory.Build.props new file mode 100644 index 000000000..f699838f7 --- /dev/null +++ b/generators/Directory.Build.props @@ -0,0 +1,5 @@ + + + + + From 745b3a49396b476bc09f66e80cbf28fc70f53aac Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Sun, 11 Jan 2026 00:49:39 +0100 Subject: [PATCH 52/99] Remove ExperimentalAttribute from IUnlockState --- Dalamud/Game/UnlockState/UnlockState.cs | 2 -- Dalamud/Plugin/Services/IUnlockState.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/Dalamud/Game/UnlockState/UnlockState.cs b/Dalamud/Game/UnlockState/UnlockState.cs index cc70a524c..939548803 100644 --- a/Dalamud/Game/UnlockState/UnlockState.cs +++ b/Dalamud/Game/UnlockState/UnlockState.cs @@ -22,8 +22,6 @@ using PublicContentSheet = Lumina.Excel.Sheets.PublicContent; namespace Dalamud.Game.UnlockState; -#pragma warning disable Dalamud001 - /// /// This class provides unlock state of various content in the game. /// diff --git a/Dalamud/Plugin/Services/IUnlockState.cs b/Dalamud/Plugin/Services/IUnlockState.cs index 0409843c4..6703ece2e 100644 --- a/Dalamud/Plugin/Services/IUnlockState.cs +++ b/Dalamud/Plugin/Services/IUnlockState.cs @@ -10,7 +10,6 @@ namespace Dalamud.Plugin.Services; /// /// Interface for determining unlock state of various content in the game. /// -[Experimental("Dalamud001")] public interface IUnlockState : IDalamudService { /// From c1df0da9beaec38c7132e519c60c04e56ec0caef Mon Sep 17 00:00:00 2001 From: goaaats Date: Sun, 11 Jan 2026 13:18:32 +0100 Subject: [PATCH 53/99] build: 14.0.1.0 --- Dalamud/Dalamud.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index bb8f5af7c..287bc5322 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -6,7 +6,7 @@ XIV Launcher addon framework - 14.0.0.3 + 14.0.1.0 $(DalamudVersion) $(DalamudVersion) $(DalamudVersion) From 3b8f0bc92fa4a612a009d46cfa8cbd3c9bed41a2 Mon Sep 17 00:00:00 2001 From: bleatbot <106497096+bleatbot@users.noreply.github.com> Date: Sun, 25 Jan 2026 05:03:03 +0100 Subject: [PATCH 54/99] Update ClientStructs (#2579) Co-authored-by: github-actions[bot] --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index d83e0c13d..127047085 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit d83e0c13d3c802d4a483f373edcd129bc4802073 +Subproject commit 1270470855d6ac2d2f726b07019e21644c5658ec From b601bfdbfb72c33c5c298fe8146c3a0a7782a259 Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Sun, 25 Jan 2026 05:03:57 +0100 Subject: [PATCH 55/99] Add Quest and Leve support to IUnlockState (#2581) * Fix AgentInterfacePtr.FocusAddon * Add Quest support to IUnlockState * Reorder, bail out early in Recipe and McGuffin * Add Leve support to IUnlockState * Fix warning * Disable log spam --- .../Game/NativeWrapper/AgentInterfacePtr.cs | 2 +- Dalamud/Game/UnlockState/UnlockState.cs | 48 +++++++++++++++++-- .../Windows/Data/Widgets/UIColorWidget.cs | 2 +- Dalamud/Plugin/Services/IUnlockState.cs | 14 ++++++ 4 files changed, 60 insertions(+), 6 deletions(-) diff --git a/Dalamud/Game/NativeWrapper/AgentInterfacePtr.cs b/Dalamud/Game/NativeWrapper/AgentInterfacePtr.cs index b5a6375a9..b5e8938dd 100644 --- a/Dalamud/Game/NativeWrapper/AgentInterfacePtr.cs +++ b/Dalamud/Game/NativeWrapper/AgentInterfacePtr.cs @@ -81,7 +81,7 @@ public readonly unsafe struct AgentInterfacePtr(nint address) : IEquatable /// true when the addon was focused, false otherwise. - public readonly bool FocusAddon() => this.IsNull && this.Struct->FocusAddon(); + public readonly bool FocusAddon() => !this.IsNull && this.Struct->FocusAddon(); /// Determines whether the specified AgentInterfacePtr is equal to the current AgentInterfacePtr. /// The AgentInterfacePtr to compare with the current AgentInterfacePtr. diff --git a/Dalamud/Game/UnlockState/UnlockState.cs b/Dalamud/Game/UnlockState/UnlockState.cs index 939548803..5ccd7fadb 100644 --- a/Dalamud/Game/UnlockState/UnlockState.cs +++ b/Dalamud/Game/UnlockState/UnlockState.cs @@ -311,9 +311,12 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState } /// - public bool IsMcGuffinUnlocked(McGuffin row) + public bool IsLeveCompleted(Leve row) { - return PlayerState.Instance()->IsMcGuffinUnlocked(row.RowId); + if (!this.IsLoaded) + return false; + + return QuestManager.Instance()->IsLevequestComplete((ushort)row.RowId); } /// @@ -328,6 +331,15 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState return this.IsUnlockLinkUnlocked(row.UnlockLink); } + /// + public bool IsMcGuffinUnlocked(McGuffin row) + { + if (!this.IsLoaded) + return false; + + return PlayerState.Instance()->IsMcGuffinUnlocked(row.RowId); + } + /// public bool IsMountUnlocked(Mount row) { @@ -376,9 +388,21 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState return UIState.IsPublicContentUnlocked(row.RowId); } + /// + public bool IsQuestCompleted(Quest row) + { + if (!this.IsLoaded) + return false; + + return QuestManager.IsQuestComplete(row.RowId); + } + /// public bool IsRecipeUnlocked(Recipe row) { + if (!this.IsLoaded) + return false; + return this.recipeData.IsRecipeUnlocked(row); } @@ -509,6 +533,9 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState if (rowRef.TryGetValue(out var itemRow)) return this.IsItemUnlocked(itemRow); + if (rowRef.TryGetValue(out var leveRow)) + return this.IsLeveCompleted(leveRow); + if (rowRef.TryGetValue(out var mjiLandmarkRow)) return this.IsMJILandmarkUnlocked(mjiLandmarkRow); @@ -536,6 +563,9 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState if (rowRef.TryGetValue(out var publicContentRow)) return this.IsPublicContentUnlocked(publicContentRow); + if (rowRef.TryGetValue(out var questRow)) + return this.IsQuestCompleted(questRow); + if (rowRef.TryGetValue(out var recipeRow)) return this.IsRecipeUnlocked(recipeRow); @@ -596,6 +626,8 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState if (!this.IsLoaded) return; + Log.Verbose("Checking for new unlocks..."); + this.UpdateUnlocksForSheet(); this.UpdateUnlocksForSheet(); this.UpdateUnlocksForSheet(); @@ -629,6 +661,7 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState this.UpdateUnlocksForSheet(); this.UpdateUnlocksForSheet(); this.UpdateUnlocksForSheet(); + this.UpdateUnlocksForSheet(); this.UpdateUnlocksForSheet(); this.UpdateUnlocksForSheet(); this.UpdateUnlocksForSheet(); @@ -637,6 +670,7 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState // Not implemented: // - DescriptionPage: quite complex // - QuestAcceptAdditionCondition: ignored + // - Leve: AgentUpdateFlag.UnlocksUpdate is not set and the completed status can be unset again! // For some other day: // - FishingSpot @@ -676,7 +710,7 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState unlockedRowIds.Add(row.RowId); - Log.Verbose($"Unlock detected: {typeof(T).Name}#{row.RowId}"); + // Log.Verbose($"Unlock detected: {typeof(T).Name}#{row.RowId}"); foreach (var action in Delegate.EnumerateInvocationList(this.Unlock)) { @@ -796,7 +830,7 @@ internal class UnlockStatePluginScoped : IInternalDisposableService, IUnlockStat public bool IsItemUnlocked(Item row) => this.unlockStateService.IsItemUnlocked(row); /// - public bool IsMcGuffinUnlocked(McGuffin row) => this.unlockStateService.IsMcGuffinUnlocked(row); + public bool IsLeveCompleted(Leve row) => this.unlockStateService.IsLeveCompleted(row); /// public bool IsMJILandmarkUnlocked(MJILandmark row) => this.unlockStateService.IsMJILandmarkUnlocked(row); @@ -804,6 +838,9 @@ internal class UnlockStatePluginScoped : IInternalDisposableService, IUnlockStat /// public bool IsMKDLoreUnlocked(MKDLore row) => this.unlockStateService.IsMKDLoreUnlocked(row); + /// + public bool IsMcGuffinUnlocked(McGuffin row) => this.unlockStateService.IsMcGuffinUnlocked(row); + /// public bool IsMountUnlocked(Mount row) => this.unlockStateService.IsMountUnlocked(row); @@ -822,6 +859,9 @@ internal class UnlockStatePluginScoped : IInternalDisposableService, IUnlockStat /// public bool IsPublicContentUnlocked(PublicContentSheet row) => this.unlockStateService.IsPublicContentUnlocked(row); + /// + public bool IsQuestCompleted(Quest row) => this.unlockStateService.IsQuestCompleted(row); + /// public bool IsRecipeUnlocked(Recipe row) => this.unlockStateService.IsRecipeUnlocked(row); diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs index dc1ab4e30..bc6e5376c 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs @@ -3,11 +3,11 @@ using System.Numerics; using System.Text; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Utility.Raii; using Dalamud.Data; using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification.Internal; using Dalamud.Interface.ImGuiSeStringRenderer.Internal; +using Dalamud.Interface.Utility.Raii; using Lumina.Excel.Sheets; diff --git a/Dalamud/Plugin/Services/IUnlockState.cs b/Dalamud/Plugin/Services/IUnlockState.cs index 6703ece2e..f51222ba1 100644 --- a/Dalamud/Plugin/Services/IUnlockState.cs +++ b/Dalamud/Plugin/Services/IUnlockState.cs @@ -205,6 +205,13 @@ public interface IUnlockState : IDalamudService /// if unlocked; otherwise, . bool IsItemUnlocked(Item row); + /// + /// Determines whether the specified Leve is completed. + /// + /// The Leve row to check. + /// if completed; otherwise, . + bool IsLeveCompleted(Leve row); + /// /// Determines whether the specified McGuffin is unlocked. /// @@ -268,6 +275,13 @@ public interface IUnlockState : IDalamudService /// if unlocked; otherwise, . bool IsPublicContentUnlocked(PublicContent row); + /// + /// Determines whether the specified Quest is completed. + /// + /// The Quest row to check. + /// if completed; otherwise, . + bool IsQuestCompleted(Quest row); + /// /// Determines whether the specified Recipe is unlocked. /// From 61423f1791b04fb561b91fef67c4decc5e4200a5 Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Sun, 25 Jan 2026 05:06:25 +0100 Subject: [PATCH 56/99] Fix being unable to edit TitleBgCollapsed (#2589) Fixes #999 --- Dalamud/Interface/Windowing/Window.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs index 3cbd1a521..dab3506c0 100644 --- a/Dalamud/Interface/Windowing/Window.cs +++ b/Dalamud/Interface/Windowing/Window.cs @@ -11,6 +11,7 @@ using Dalamud.Game.ClientState.Keys; using Dalamud.Interface.Colors; using Dalamud.Interface.Components; using Dalamud.Interface.Internal; +using Dalamud.Interface.Internal.Windows.StyleEditor; using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; @@ -461,7 +462,7 @@ public abstract class Window ImGuiHelpers.ForceNextWindowMainViewport(); var wasFocused = this.IsFocused; - if (wasFocused) + if (wasFocused && this is not StyleEditorWindow) { var style = ImGui.GetStyle(); var focusedHeaderColor = style.Colors[(int)ImGuiCol.TitleBgActive]; @@ -616,7 +617,7 @@ public abstract class Window this.DrawTitleBarButtons(); } - if (wasFocused) + if (wasFocused && this is not StyleEditorWindow) { ImGui.PopStyleColor(); } From 951290cac7f27ca67b76391649c5d9f0c38929bf Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Sun, 25 Jan 2026 05:06:55 +0100 Subject: [PATCH 57/99] Fix EnumGenerator configuration mapping (#2590) --- Dalamud.sln | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Dalamud.sln b/Dalamud.sln index 3b1c4fd91..758253b9c 100644 --- a/Dalamud.sln +++ b/Dalamud.sln @@ -184,18 +184,18 @@ Global {88FB719B-EB41-73C5-8D25-C03E0C69904F}.Debug|Any CPU.Build.0 = Debug|Any CPU {88FB719B-EB41-73C5-8D25-C03E0C69904F}.Release|Any CPU.ActiveCfg = Release|Any CPU {88FB719B-EB41-73C5-8D25-C03E0C69904F}.Release|Any CPU.Build.0 = Release|Any CPU - {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Debug|Any CPU.ActiveCfg = Debug|x64 - {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Debug|Any CPU.Build.0 = Debug|x64 - {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Release|Any CPU.ActiveCfg = Release|x64 - {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Release|Any CPU.Build.0 = Release|x64 - {8CDAEB2D-5022-450A-A97F-181C6270185F}.Debug|Any CPU.ActiveCfg = Debug|x64 - {8CDAEB2D-5022-450A-A97F-181C6270185F}.Debug|Any CPU.Build.0 = Debug|x64 - {8CDAEB2D-5022-450A-A97F-181C6270185F}.Release|Any CPU.ActiveCfg = Release|x64 - {8CDAEB2D-5022-450A-A97F-181C6270185F}.Release|Any CPU.Build.0 = Release|x64 - {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Debug|Any CPU.ActiveCfg = Debug|x64 - {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Debug|Any CPU.Build.0 = Debug|x64 - {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Release|Any CPU.ActiveCfg = Release|x64 - {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Release|Any CPU.Build.0 = Release|x64 + {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27AA9F87-D2AA-41D9-A559-0F1EBA38C5F8}.Release|Any CPU.Build.0 = Release|Any CPU + {8CDAEB2D-5022-450A-A97F-181C6270185F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8CDAEB2D-5022-450A-A97F-181C6270185F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8CDAEB2D-5022-450A-A97F-181C6270185F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8CDAEB2D-5022-450A-A97F-181C6270185F}.Release|Any CPU.Build.0 = Release|Any CPU + {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F5D92D2D-D36F-4471-B657-8B9AA6C98AD6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From ac7c4e889a853c61a7b08b71cfb73e57000a304e Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Sun, 25 Jan 2026 12:40:51 +0100 Subject: [PATCH 58/99] Write troubleshooting to json file --- Dalamud/Support/Troubleshooting.cs | 8 ++++++++ DalamudCrashHandler/DalamudCrashHandler.cpp | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Dalamud/Support/Troubleshooting.cs b/Dalamud/Support/Troubleshooting.cs index 2dd0fb623..e94252027 100644 --- a/Dalamud/Support/Troubleshooting.cs +++ b/Dalamud/Support/Troubleshooting.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; @@ -85,6 +86,13 @@ public static class Troubleshooting var encodedPayload = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload))); Log.Information($"TROUBLESHOOTING:{encodedPayload}"); + + File.WriteAllText( + Path.Join( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "XIVLauncher", + "dalamud.troubleshooting.json"), + JsonConvert.SerializeObject(payload, Formatting.Indented)); } catch (Exception ex) { diff --git a/DalamudCrashHandler/DalamudCrashHandler.cpp b/DalamudCrashHandler/DalamudCrashHandler.cpp index f28715dc1..b72733983 100644 --- a/DalamudCrashHandler/DalamudCrashHandler.cpp +++ b/DalamudCrashHandler/DalamudCrashHandler.cpp @@ -476,6 +476,7 @@ void export_tspack(HWND hWndParent, const std::filesystem::path& logDir, const s "launcher.log", // XIVLauncher.Core for [mostly] Linux "patcher.log", "dalamud.log", + "dalamud.troubleshooting.json", "dalamud.injector.log", "dalamud.boot.log", "aria.log", @@ -693,7 +694,7 @@ void restart_game_using_injector(int nRadioButton, const std::vector cpui; int nIds_; From b9c4c97eba8c6c83d6511452e294ca1f862b700d Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Sun, 25 Jan 2026 16:23:24 +0100 Subject: [PATCH 59/99] Add timestamp to TroubleshootingPayload --- Dalamud/Support/Troubleshooting.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dalamud/Support/Troubleshooting.cs b/Dalamud/Support/Troubleshooting.cs index e94252027..f9e084db8 100644 --- a/Dalamud/Support/Troubleshooting.cs +++ b/Dalamud/Support/Troubleshooting.cs @@ -69,6 +69,7 @@ public static class Troubleshooting { var payload = new TroubleshootingPayload { + Timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), LoadedPlugins = pluginManager?.InstalledPlugins?.Select(x => x.Manifest as LocalPluginManifest)?.OrderByDescending(x => x.InternalName).ToArray(), PluginStates = pluginManager?.InstalledPlugins?.Where(x => !x.IsDev).ToDictionary(x => x.Manifest.InternalName, x => x.IsBanned ? "Banned" : x.State.ToString()), EverStartedLoadingPlugins = pluginManager?.InstalledPlugins.Where(x => x.HasEverStartedLoad).Select(x => x.InternalName).ToList(), @@ -111,6 +112,8 @@ public static class Troubleshooting private class TroubleshootingPayload { + public long Timestamp { get; set; } + public LocalPluginManifest[]? LoadedPlugins { get; set; } public Dictionary? PluginStates { get; set; } From 672636c3bf2fa995c95aff2ab70ad4af3475f605 Mon Sep 17 00:00:00 2001 From: Infi Date: Mon, 26 Jan 2026 04:21:03 +0100 Subject: [PATCH 60/99] Remove UiDebug V1 in favor of V2 (#2586) * - Remove UiDebug1 in favor of UiDebug2 * - Remove all mentions of 2 --- Dalamud/Interface/Internal/UiDebug.cs | 675 ------------------ .../Browsing/AddonTree.AtkValues.cs | 4 +- .../Browsing/AddonTree.FieldNames.cs | 4 +- .../Browsing/AddonTree.cs | 8 +- .../{UiDebug2 => UiDebug}/Browsing/Events.cs | 2 +- .../Browsing/NodeTree.ClippingMask.cs | 2 +- .../Browsing/NodeTree.Collision.cs | 2 +- .../Browsing/NodeTree.Component.cs | 4 +- .../Browsing/NodeTree.Counter.cs | 4 +- .../Browsing/NodeTree.Editor.cs | 6 +- .../Browsing/NodeTree.Image.cs | 4 +- .../Browsing/NodeTree.NineGrid.cs | 4 +- .../Browsing/NodeTree.Res.cs | 12 +- .../Browsing/NodeTree.Text.cs | 4 +- .../Browsing/TimelineTree.KeyGroupColumn.cs | 2 +- .../Browsing/TimelineTree.cs | 4 +- .../{UiDebug2 => UiDebug}/ElementSelector.cs | 20 +- .../{UiDebug2 => UiDebug}/Popout.Addon.cs | 4 +- .../{UiDebug2 => UiDebug}/Popout.Node.cs | 6 +- .../UiDebug.Sidebar.cs} | 6 +- .../UiDebug2.cs => UiDebug/UiDebug.cs} | 12 +- .../{UiDebug2 => UiDebug}/Utility/Gui.cs | 4 +- .../Utility/NodeBounds.cs | 2 +- .../Internal/Windows/Data/DataWindow.cs | 1 - .../Data/Widgets/AddonInspectorWidget.cs | 6 +- .../Data/Widgets/AddonInspectorWidget2.cs | 35 - Dalamud/Plugin/Services/ITextureProvider.cs | 2 +- 27 files changed, 64 insertions(+), 775 deletions(-) delete mode 100644 Dalamud/Interface/Internal/UiDebug.cs rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/AddonTree.AtkValues.cs (97%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/AddonTree.FieldNames.cs (98%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/AddonTree.cs (96%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/Events.cs (97%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/NodeTree.ClippingMask.cs (95%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/NodeTree.Collision.cs (93%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/NodeTree.Component.cs (99%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/NodeTree.Counter.cs (90%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/NodeTree.Editor.cs (98%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/NodeTree.Image.cs (98%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/NodeTree.NineGrid.cs (98%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/NodeTree.Res.cs (97%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/NodeTree.Text.cs (96%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/TimelineTree.KeyGroupColumn.cs (98%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Browsing/TimelineTree.cs (99%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/ElementSelector.cs (95%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Popout.Addon.cs (93%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Popout.Node.cs (93%) rename Dalamud/Interface/Internal/{UiDebug2/UiDebug2.Sidebar.cs => UiDebug/UiDebug.Sidebar.cs} (98%) rename Dalamud/Interface/Internal/{UiDebug2/UiDebug2.cs => UiDebug/UiDebug.cs} (92%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Utility/Gui.cs (97%) rename Dalamud/Interface/Internal/{UiDebug2 => UiDebug}/Utility/NodeBounds.cs (99%) delete mode 100644 Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget2.cs diff --git a/Dalamud/Interface/Internal/UiDebug.cs b/Dalamud/Interface/Internal/UiDebug.cs deleted file mode 100644 index a79cc1880..000000000 --- a/Dalamud/Interface/Internal/UiDebug.cs +++ /dev/null @@ -1,675 +0,0 @@ -using System.Numerics; - -using Dalamud.Bindings.ImGui; -using Dalamud.Game; -using Dalamud.Game.Gui; -using Dalamud.Interface.ImGuiSeStringRenderer.Internal; -using Dalamud.Interface.Textures.Internal; -using Dalamud.Interface.Utility; -using Dalamud.Utility; - -using FFXIVClientStructs.FFXIV.Client.System.String; -using FFXIVClientStructs.FFXIV.Client.UI.Misc; -using FFXIVClientStructs.FFXIV.Component.GUI; - -// Customised version of https://github.com/aers/FFXIVUIDebug - -namespace Dalamud.Interface.Internal; - -/// -/// This class displays a debug window to inspect native addons. -/// -internal unsafe class UiDebug -{ - private const int UnitListCount = 18; - - private readonly bool[] selectedInList = new bool[UnitListCount]; - private readonly string[] listNames = - [ - "Depth Layer 1", - "Depth Layer 2", - "Depth Layer 3", - "Depth Layer 4", - "Depth Layer 5", - "Depth Layer 6", - "Depth Layer 7", - "Depth Layer 8", - "Depth Layer 9", - "Depth Layer 10", - "Depth Layer 11", - "Depth Layer 12", - "Depth Layer 13", - "Loaded Units", - "Focused Units", - "Units 16", - "Units 17", - "Units 18", - ]; - - private bool doingSearch; - private string searchInput = string.Empty; - private AtkUnitBase* selectedUnitBase = null; - - /// - /// Initializes a new instance of the class. - /// - public UiDebug() - { - } - - /// - /// Renders this window. - /// - public void Draw() - { - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(3, 2)); - ImGui.BeginChild("st_uiDebug_unitBaseSelect"u8, new Vector2(250, -1), true); - - ImGui.SetNextItemWidth(-1); - ImGui.InputTextWithHint("###atkUnitBaseSearch"u8, "Search"u8, ref this.searchInput, 0x20); - - this.DrawUnitBaseList(); - ImGui.EndChild(); - if (this.selectedUnitBase != null) - { - ImGui.SameLine(); - ImGui.BeginChild("st_uiDebug_selectedUnitBase"u8, new Vector2(-1, -1), true); - this.DrawUnitBase(this.selectedUnitBase); - ImGui.EndChild(); - } - - ImGui.PopStyleVar(); - } - - private void DrawUnitBase(AtkUnitBase* atkUnitBase) - { - var isVisible = atkUnitBase->IsVisible; - var addonName = atkUnitBase->NameString; - var agent = Service.Get().FindAgentInterface(atkUnitBase); - - ImGui.Text(addonName); - ImGui.SameLine(); - ImGui.PushStyleColor(ImGuiCol.Text, isVisible ? 0xFF00FF00 : 0xFF0000FF); - ImGui.Text(isVisible ? "Visible" : "Not Visible"); - ImGui.PopStyleColor(); - - ImGui.SameLine(ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - 25); - if (ImGui.SmallButton("V"u8)) - { - atkUnitBase->IsVisible = !atkUnitBase->IsVisible; - } - - ImGui.Separator(); - ImGuiHelpers.ClickToCopyText($"Address: {(nint)atkUnitBase:X}", $"{(nint)atkUnitBase:X}"); - ImGuiHelpers.ClickToCopyText($"Agent: {(nint)agent:X}", $"{(nint)agent:X}"); - ImGui.Separator(); - - ImGui.Text($"Position: [ {atkUnitBase->X} , {atkUnitBase->Y} ]"); - ImGui.Text($"Scale: {atkUnitBase->Scale * 100}%"); - ImGui.Text($"Widget Count {atkUnitBase->UldManager.ObjectCount}"); - - ImGui.Separator(); - - object addonObj = *atkUnitBase; - - Util.ShowStruct(addonObj, (ulong)atkUnitBase); - - ImGui.Dummy(new Vector2(25 * ImGui.GetIO().FontGlobalScale)); - ImGui.Separator(); - if (atkUnitBase->RootNode != null) - this.PrintNode(atkUnitBase->RootNode); - - if (atkUnitBase->UldManager.NodeListCount > 0) - { - ImGui.Dummy(new Vector2(25 * ImGui.GetIO().FontGlobalScale)); - ImGui.Separator(); - ImGui.PushStyleColor(ImGuiCol.Text, 0xFFFFAAAA); - if (ImGui.TreeNode($"Node List##{(ulong)atkUnitBase:X}")) - { - ImGui.PopStyleColor(); - - for (var j = 0; j < atkUnitBase->UldManager.NodeListCount; j++) - { - this.PrintNode(atkUnitBase->UldManager.NodeList[j], false, $"[{j}] "); - } - - ImGui.TreePop(); - } - else - { - ImGui.PopStyleColor(); - } - } - } - - private void PrintNode(AtkResNode* node, bool printSiblings = true, string treePrefix = "") - { - if (node == null) - return; - - if ((int)node->Type < 1000) - this.PrintSimpleNode(node, treePrefix); - else - this.PrintComponentNode(node, treePrefix); - - if (printSiblings) - { - var prevNode = node; - while ((prevNode = prevNode->PrevSiblingNode) != null) - this.PrintNode(prevNode, false, "prev "); - - var nextNode = node; - while ((nextNode = nextNode->NextSiblingNode) != null) - this.PrintNode(nextNode, false, "next "); - } - } - - private void PrintSimpleNode(AtkResNode* node, string treePrefix) - { - var popped = false; - var isVisible = node->NodeFlags.HasFlag(NodeFlags.Visible); - - if (isVisible) - ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0, 255, 0, 255)); - - if (ImGui.TreeNode($"{treePrefix}{node->Type} Node (ptr = {(long)node:X})###{(long)node}")) - { - if (ImGui.IsItemHovered()) - this.DrawOutline(node); - - if (isVisible) - { - ImGui.PopStyleColor(); - popped = true; - } - - ImGui.Text("Node: "u8); - ImGui.SameLine(); - ImGuiHelpers.ClickToCopyText($"{(ulong)node:X}"); - ImGui.SameLine(); - switch (node->Type) - { - case NodeType.Text: Util.ShowStruct(*(AtkTextNode*)node, (ulong)node); break; - case NodeType.Image: Util.ShowStruct(*(AtkImageNode*)node, (ulong)node); break; - case NodeType.Collision: Util.ShowStruct(*(AtkCollisionNode*)node, (ulong)node); break; - case NodeType.NineGrid: Util.ShowStruct(*(AtkNineGridNode*)node, (ulong)node); break; - case NodeType.ClippingMask: Util.ShowStruct(*(AtkClippingMaskNode*)node, (ulong)node); break; - case NodeType.Counter: Util.ShowStruct(*(AtkCounterNode*)node, (ulong)node); break; - default: Util.ShowStruct(*node, (ulong)node); break; - } - - this.PrintResNode(node); - - if (node->ChildNode != null) - this.PrintNode(node->ChildNode); - - switch (node->Type) - { - case NodeType.Text: - var textNode = (AtkTextNode*)node; - ImGui.Text("text: "u8); - ImGui.SameLine(); - Service.Get().Draw(textNode->NodeText); - - ImGui.InputText($"Replace Text##{(ulong)textNode:X}", new(textNode->NodeText.StringPtr, (int)textNode->NodeText.BufSize)); - - ImGui.SameLine(); - if (ImGui.Button($"Encode##{(ulong)textNode:X}")) - { - using var tmp = new Utf8String(); - RaptureTextModule.Instance()->MacroEncoder.EncodeString(&tmp, textNode->NodeText.StringPtr); - textNode->NodeText.Copy(&tmp); - } - - ImGui.SameLine(); - if (ImGui.Button($"Decode##{(ulong)textNode:X}")) - textNode->NodeText.SetString(textNode->NodeText.StringPtr.AsReadOnlySeStringSpan().ToString()); - - ImGui.Text($"AlignmentType: {(AlignmentType)textNode->AlignmentFontType} FontSize: {textNode->FontSize}"); - int b = textNode->AlignmentFontType; - if (ImGui.InputInt($"###setAlignment{(ulong)textNode:X}", ref b, 1)) - { - while (b > byte.MaxValue) b -= byte.MaxValue; - while (b < byte.MinValue) b += byte.MaxValue; - textNode->AlignmentFontType = (byte)b; - textNode->AtkResNode.DrawFlags |= 0x1; - } - - ImGui.Text($"Color: #{textNode->TextColor.R:X2}{textNode->TextColor.G:X2}{textNode->TextColor.B:X2}{textNode->TextColor.A:X2}"); - ImGui.SameLine(); - ImGui.Text($"EdgeColor: #{textNode->EdgeColor.R:X2}{textNode->EdgeColor.G:X2}{textNode->EdgeColor.B:X2}{textNode->EdgeColor.A:X2}"); - ImGui.SameLine(); - ImGui.Text($"BGColor: #{textNode->BackgroundColor.R:X2}{textNode->BackgroundColor.G:X2}{textNode->BackgroundColor.B:X2}{textNode->BackgroundColor.A:X2}"); - - ImGui.Text($"TextFlags: {textNode->TextFlags}"); - - break; - case NodeType.Counter: - var counterNode = (AtkCounterNode*)node; - ImGui.Text("text: "u8); - ImGui.SameLine(); - Service.Get().Draw(counterNode->NodeText); - break; - case NodeType.Image: - var imageNode = (AtkImageNode*)node; - PrintTextureInfo(imageNode->PartsList, imageNode->PartId); - break; - case NodeType.NineGrid: - var ngNode = (AtkNineGridNode*)node; - PrintTextureInfo(ngNode->PartsList, ngNode->PartId); - break; - case NodeType.ClippingMask: - var cmNode = (AtkClippingMaskNode*)node; - PrintTextureInfo(cmNode->PartsList, cmNode->PartId); - break; - } - - ImGui.TreePop(); - } - else if (ImGui.IsItemHovered()) - { - this.DrawOutline(node); - } - - if (isVisible && !popped) - ImGui.PopStyleColor(); - - static void PrintTextureInfo(AtkUldPartsList* partsList, uint partId) - { - if (partsList != null) - { - if (partId > partsList->PartCount) - { - ImGui.Text("part id > part count?"u8); - } - else - { - var textureInfo = partsList->Parts[partId].UldAsset; - var texType = textureInfo->AtkTexture.TextureType; - ImGui.Text( - $"texture type: {texType} part_id={partId} part_id_count={partsList->PartCount}"); - if (texType == TextureType.Resource) - { - ImGui.Text( - $"texture path: {textureInfo->AtkTexture.Resource->TexFileResourceHandle->ResourceHandle.FileName}"); - var kernelTexture = textureInfo->AtkTexture.Resource->KernelTextureObject; - - if (ImGui.TreeNode($"Texture##{(ulong)kernelTexture->D3D11ShaderResourceView:X}")) - { - ImGui.Image( - new ImTextureID(kernelTexture->D3D11ShaderResourceView), - new Vector2(kernelTexture->ActualWidth, kernelTexture->ActualHeight)); - ImGui.TreePop(); - } - } - else if (texType == TextureType.KernelTexture) - { - if (ImGui.TreeNode( - $"Texture##{(ulong)textureInfo->AtkTexture.KernelTexture->D3D11ShaderResourceView:X}")) - { - ImGui.Image( - new ImTextureID(textureInfo->AtkTexture.KernelTexture->D3D11ShaderResourceView), - new Vector2( - textureInfo->AtkTexture.KernelTexture->ActualWidth, - textureInfo->AtkTexture.KernelTexture->ActualHeight)); - ImGui.TreePop(); - } - } - - if (ImGui.Button($"Replace with a random image##{(ulong)textureInfo:X}")) - { - var texm = Service.Get(); - texm.Shared - .GetFromGame( - Random.Shared.Next(0, 1) == 0 - ? $"ui/loadingimage/-nowloading_base{Random.Shared.Next(1, 33)}.tex" - : $"ui/loadingimage/-nowloading_base{Random.Shared.Next(1, 33)}_hr1.tex") - .RentAsync() - .ContinueWith( - r => Service.Get().RunOnFrameworkThread( - () => - { - if (!r.IsCompletedSuccessfully) - return; - - using (r.Result) - { - textureInfo->AtkTexture.ReleaseTexture(); - textureInfo->AtkTexture.KernelTexture = - texm.ConvertToKernelTexture(r.Result); - textureInfo->AtkTexture.TextureType = TextureType.KernelTexture; - } - })); - } - } - } - else - { - ImGui.Text("no texture loaded"u8); - } - } - } - - private void PrintComponentNode(AtkResNode* node, string treePrefix) - { - var compNode = (AtkComponentNode*)node; - - var popped = false; - var isVisible = node->NodeFlags.HasFlag(NodeFlags.Visible); - - var componentInfo = compNode->Component->UldManager; - - var childCount = componentInfo.NodeListCount; - - var objectInfo = (AtkUldComponentInfo*)componentInfo.Objects; - if (objectInfo == null) - { - return; - } - - if (isVisible) - ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(0, 255, 0, 255)); - - if (ImGui.TreeNode($"{treePrefix}{objectInfo->ComponentType} Component Node (ptr = {(long)node:X}, component ptr = {(long)compNode->Component:X}) child count = {childCount} ###{(long)node}")) - { - if (ImGui.IsItemHovered()) - this.DrawOutline(node); - - if (isVisible) - { - ImGui.PopStyleColor(); - popped = true; - } - - ImGui.Text("Node: "u8); - ImGui.SameLine(); - ImGuiHelpers.ClickToCopyText($"{(ulong)node:X}"); - ImGui.SameLine(); - Util.ShowStruct(*compNode, (ulong)compNode); - ImGui.Text("Component: "u8); - ImGui.SameLine(); - ImGuiHelpers.ClickToCopyText($"{(ulong)compNode->Component:X}"); - ImGui.SameLine(); - - switch (objectInfo->ComponentType) - { - case ComponentType.Button: Util.ShowStruct(*(AtkComponentButton*)compNode->Component, (ulong)compNode->Component); break; - case ComponentType.Slider: Util.ShowStruct(*(AtkComponentSlider*)compNode->Component, (ulong)compNode->Component); break; - case ComponentType.Window: Util.ShowStruct(*(AtkComponentWindow*)compNode->Component, (ulong)compNode->Component); break; - case ComponentType.CheckBox: Util.ShowStruct(*(AtkComponentCheckBox*)compNode->Component, (ulong)compNode->Component); break; - case ComponentType.GaugeBar: Util.ShowStruct(*(AtkComponentGaugeBar*)compNode->Component, (ulong)compNode->Component); break; - case ComponentType.RadioButton: Util.ShowStruct(*(AtkComponentRadioButton*)compNode->Component, (ulong)compNode->Component); break; - case ComponentType.TextInput: Util.ShowStruct(*(AtkComponentTextInput*)compNode->Component, (ulong)compNode->Component); break; - case ComponentType.Icon: Util.ShowStruct(*(AtkComponentIcon*)compNode->Component, (ulong)compNode->Component); break; - default: Util.ShowStruct(*compNode->Component, (ulong)compNode->Component); break; - } - - this.PrintResNode(node); - this.PrintNode(componentInfo.RootNode); - - switch (objectInfo->ComponentType) - { - case ComponentType.TextInput: - var textInputComponent = (AtkComponentTextInput*)compNode->Component; - ImGui.Text("InputBase Text1: "u8); - ImGui.SameLine(); - Service.Get().Draw(textInputComponent->AtkComponentInputBase.EvaluatedString); - - ImGui.Text("InputBase Text2: "u8); - ImGui.SameLine(); - Service.Get().Draw(textInputComponent->AtkComponentInputBase.RawString); - - // ImGui.Text("Text1: "u8); - // ImGui.SameLine(); - // Service.Get().Draw(textInputComponent->UnkText01); - // - // ImGui.Text("Text2: "u8); - // ImGui.SameLine(); - // Service.Get().Draw(textInputComponent->UnkText02); - - ImGui.Text("AvailableLines: "u8); - ImGui.SameLine(); - Service.Get().Draw(textInputComponent->AvailableLines); - - ImGui.Text("HighlightedAutoTranslateOptionColorPrefix: "u8); - ImGui.SameLine(); - Service.Get().Draw(textInputComponent->HighlightedAutoTranslateOptionColorPrefix); - - ImGui.Text("HighlightedAutoTranslateOptionColorSuffix: "u8); - ImGui.SameLine(); - Service.Get().Draw(textInputComponent->HighlightedAutoTranslateOptionColorSuffix); - break; - } - - ImGui.PushStyleColor(ImGuiCol.Text, 0xFFFFAAAA); - if (ImGui.TreeNode($"Node List##{(ulong)node:X}")) - { - ImGui.PopStyleColor(); - - for (var i = 0; i < compNode->Component->UldManager.NodeListCount; i++) - { - this.PrintNode(compNode->Component->UldManager.NodeList[i], false, $"[{i}] "); - } - - ImGui.TreePop(); - } - else - { - ImGui.PopStyleColor(); - } - - ImGui.TreePop(); - } - else if (ImGui.IsItemHovered()) - { - this.DrawOutline(node); - } - - if (isVisible && !popped) - ImGui.PopStyleColor(); - } - - private void PrintResNode(AtkResNode* node) - { - ImGui.Text($"NodeID: {node->NodeId}"); - ImGui.SameLine(); - if (ImGui.SmallButton($"T:Visible##{(ulong)node:X}")) - { - node->NodeFlags ^= NodeFlags.Visible; - } - - ImGui.SameLine(); - if (ImGui.SmallButton($"C:Ptr##{(ulong)node:X}")) - { - ImGui.SetClipboardText($"{(ulong)node:X}"); - } - - ImGui.Text( - $"X: {node->X} Y: {node->Y} " + - $"ScaleX: {node->ScaleX} ScaleY: {node->ScaleY} " + - $"Rotation: {node->Rotation} " + - $"Width: {node->Width} Height: {node->Height} " + - $"OriginX: {node->OriginX} OriginY: {node->OriginY}"); - ImGui.Text( - $"RGBA: 0x{node->Color.R:X2}{node->Color.G:X2}{node->Color.B:X2}{node->Color.A:X2} " + - $"AddRGB: {node->AddRed} {node->AddGreen} {node->AddBlue} " + - $"MultiplyRGB: {node->MultiplyRed} {node->MultiplyGreen} {node->MultiplyBlue}"); - } - - private bool DrawUnitListHeader(int index, ushort count, ulong ptr, bool highlight) - { - ImGui.PushStyleColor(ImGuiCol.Text, highlight ? 0xFFAAAA00 : 0xFFFFFFFF); - if (!string.IsNullOrEmpty(this.searchInput) && !this.doingSearch) - { - ImGui.SetNextItemOpen(true, ImGuiCond.Always); - } - else if (this.doingSearch && string.IsNullOrEmpty(this.searchInput)) - { - ImGui.SetNextItemOpen(false, ImGuiCond.Always); - } - - var treeNode = ImGui.TreeNode($"{this.listNames[index]}##unitList_{index}"); - ImGui.PopStyleColor(); - - ImGui.SameLine(); - ImGui.TextDisabled($"C:{count} {ptr:X}"); - return treeNode; - } - - private void DrawUnitBaseList() - { - var foundSelected = false; - var noResults = true; - var stage = AtkStage.Instance(); - - var unitManagers = &stage->RaptureAtkUnitManager->AtkUnitManager.DepthLayerOneList; - - var searchStr = this.searchInput; - var searching = !string.IsNullOrEmpty(searchStr); - - for (var i = 0; i < UnitListCount; i++) - { - var headerDrawn = false; - - var highlight = this.selectedUnitBase != null && this.selectedInList[i]; - this.selectedInList[i] = false; - var unitManager = &unitManagers[i]; - - var headerOpen = true; - - if (!searching) - { - headerOpen = this.DrawUnitListHeader(i, unitManager->Count, (ulong)unitManager, highlight); - headerDrawn = true; - noResults = false; - } - - for (var j = 0; j < unitManager->Count && headerOpen; j++) - { - AtkUnitBase* unitBase = unitManager->Entries[j]; - if (this.selectedUnitBase != null && unitBase == this.selectedUnitBase) - { - this.selectedInList[i] = true; - foundSelected = true; - } - - var name = unitBase->NameString; - if (searching) - { - if (name == null || !name.Contains(searchStr, StringComparison.InvariantCultureIgnoreCase)) continue; - } - - noResults = false; - if (!headerDrawn) - { - headerOpen = this.DrawUnitListHeader(i, unitManager->Count, (ulong)unitManager, highlight); - headerDrawn = true; - } - - if (headerOpen) - { - var visible = unitBase->IsVisible; - ImGui.PushStyleColor(ImGuiCol.Text, visible ? 0xFF00FF00 : 0xFF999999); - - if (ImGui.Selectable($"{name}##list{i}-{(ulong)unitBase:X}_{j}", this.selectedUnitBase == unitBase)) - { - this.selectedUnitBase = unitBase; - foundSelected = true; - this.selectedInList[i] = true; - } - - ImGui.PopStyleColor(); - } - } - - if (headerDrawn && headerOpen) - { - ImGui.TreePop(); - } - - if (this.selectedInList[i] == false && this.selectedUnitBase != null) - { - for (var j = 0; j < unitManager->Count; j++) - { - AtkUnitBase* unitBase = unitManager->Entries[j]; - if (this.selectedUnitBase == null || unitBase != this.selectedUnitBase) continue; - this.selectedInList[i] = true; - foundSelected = true; - } - } - } - - if (noResults) - { - ImGui.TextDisabled("No Results"u8); - } - - if (!foundSelected) - { - this.selectedUnitBase = null; - } - - if (this.doingSearch && string.IsNullOrEmpty(this.searchInput)) - { - this.doingSearch = false; - } - else if (!this.doingSearch && !string.IsNullOrEmpty(this.searchInput)) - { - this.doingSearch = true; - } - } - - private Vector2 GetNodePosition(AtkResNode* node) - { - var pos = new Vector2(node->X, node->Y); - pos -= new Vector2(node->OriginX * (node->ScaleX - 1), node->OriginY * (node->ScaleY - 1)); - var par = node->ParentNode; - while (par != null) - { - pos *= new Vector2(par->ScaleX, par->ScaleY); - pos += new Vector2(par->X, par->Y); - pos -= new Vector2(par->OriginX * (par->ScaleX - 1), par->OriginY * (par->ScaleY - 1)); - par = par->ParentNode; - } - - return pos; - } - - private Vector2 GetNodeScale(AtkResNode* node) - { - if (node == null) return new Vector2(1, 1); - var scale = new Vector2(node->ScaleX, node->ScaleY); - while (node->ParentNode != null) - { - node = node->ParentNode; - scale *= new Vector2(node->ScaleX, node->ScaleY); - } - - return scale; - } - - private bool GetNodeVisible(AtkResNode* node) - { - if (node == null) return false; - while (node != null) - { - if (!node->NodeFlags.HasFlag(NodeFlags.Visible)) return false; - node = node->ParentNode; - } - - return true; - } - - private void DrawOutline(AtkResNode* node) - { - var position = this.GetNodePosition(node); - var scale = this.GetNodeScale(node); - var size = new Vector2(node->Width, node->Height) * scale; - - var nodeVisible = this.GetNodeVisible(node); - - position += ImGuiHelpers.MainViewport.Pos; - - ImGui.GetForegroundDrawList(ImGuiHelpers.MainViewport).AddRect(position, position + size, nodeVisible ? 0xFF00FF00 : 0xFF0000FF); - } -} diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/AddonTree.AtkValues.cs similarity index 97% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/AddonTree.AtkValues.cs index ed9ed2150..646d4e3ad 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/AddonTree.AtkValues.cs @@ -1,7 +1,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Internal.UiDebug2.Utility; +using Dalamud.Interface.Internal.UiDebug.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Utility; @@ -9,7 +9,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// public unsafe partial class AddonTree diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/AddonTree.FieldNames.cs similarity index 98% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/AddonTree.FieldNames.cs index 6ff58d657..3470b724b 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/AddonTree.FieldNames.cs @@ -7,9 +7,9 @@ using FFXIVClientStructs.Attributes; using FFXIVClientStructs.FFXIV.Component.GUI; using static System.Reflection.BindingFlags; -using static Dalamud.Interface.Internal.UiDebug2.UiDebug2; +using static Dalamud.Interface.Internal.UiDebug.UiDebug; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// public unsafe partial class AddonTree diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/AddonTree.cs similarity index 96% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/AddonTree.cs index 2e0874206..954755708 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/AddonTree.cs @@ -8,12 +8,12 @@ using Dalamud.Interface.Components; using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Interface.FontAwesomeIcon; -using static Dalamud.Interface.Internal.UiDebug2.ElementSelector; -using static Dalamud.Interface.Internal.UiDebug2.UiDebug2; -using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; +using static Dalamud.Interface.Internal.UiDebug.ElementSelector; +using static Dalamud.Interface.Internal.UiDebug.UiDebug; +using static Dalamud.Interface.Internal.UiDebug.Utility.Gui; using static Dalamud.Utility.Util; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A class representing an , allowing it to be browsed within an ImGui window. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/Events.cs similarity index 97% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/Events.cs index ed1926ce9..6e56c75f8 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/Events.cs @@ -9,7 +9,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Bindings.ImGui.ImGuiTableColumnFlags; using static Dalamud.Bindings.ImGui.ImGuiTableFlags; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// Class that prints the events table for a node, where applicable. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.ClippingMask.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.ClippingMask.cs similarity index 95% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.ClippingMask.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.ClippingMask.cs index cfba1a2bc..f9fb3b73d 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.ClippingMask.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.ClippingMask.cs @@ -2,7 +2,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Utility.Util; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A tree for an that can be printed and browsed via ImGui. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Collision.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Collision.cs similarity index 93% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Collision.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Collision.cs index c447afac9..d6370d33f 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Collision.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Collision.cs @@ -2,7 +2,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Utility.Util; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A tree for an that can be printed and browsed via ImGui. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Component.cs similarity index 99% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Component.cs index 13d559c11..fb4444be1 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Component.cs @@ -6,11 +6,11 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using Lumina.Text.ReadOnly; -using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; +using static Dalamud.Interface.Internal.UiDebug.Utility.Gui; using static Dalamud.Utility.Util; using static FFXIVClientStructs.FFXIV.Component.GUI.ComponentType; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A tree for an that can be printed and browsed via ImGui. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Counter.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Counter.cs similarity index 90% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Counter.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Counter.cs index 2b2adbcee..2ffcad5de 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Counter.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Counter.cs @@ -2,10 +2,10 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using Lumina.Text.ReadOnly; -using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; +using static Dalamud.Interface.Internal.UiDebug.Utility.Gui; using static Dalamud.Utility.Util; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A tree for an that can be printed and browsed via ImGui. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Editor.cs similarity index 98% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Editor.cs index d4e8e61ab..d9dd1378c 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Editor.cs @@ -3,7 +3,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; -using Dalamud.Interface.Internal.UiDebug2.Utility; +using Dalamud.Interface.Internal.UiDebug.Utility; using Dalamud.Interface.Utility.Raii; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -16,10 +16,10 @@ using static Dalamud.Bindings.ImGui.ImGuiTableColumnFlags; using static Dalamud.Bindings.ImGui.ImGuiTableFlags; using static Dalamud.Interface.ColorHelpers; using static Dalamud.Interface.FontAwesomeIcon; -using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; +using static Dalamud.Interface.Internal.UiDebug.Utility.Gui; using static Dalamud.Interface.Utility.ImGuiHelpers; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// internal unsafe partial class ResNodeTree diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Image.cs similarity index 98% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Image.cs index 45dd63b53..949197f50 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Image.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Image.cs @@ -11,11 +11,11 @@ using static Dalamud.Bindings.ImGui.ImGuiTableColumnFlags; using static Dalamud.Bindings.ImGui.ImGuiTableFlags; using static Dalamud.Bindings.ImGui.ImGuiTreeNodeFlags; using static Dalamud.Interface.ColorHelpers; -using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; +using static Dalamud.Interface.Internal.UiDebug.Utility.Gui; using static Dalamud.Utility.Util; using static FFXIVClientStructs.FFXIV.Component.GUI.TextureType; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A tree for an that can be printed and browsed via ImGui. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.NineGrid.cs similarity index 98% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.NineGrid.cs index 1c06dfb40..7d241ebdb 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.NineGrid.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.NineGrid.cs @@ -1,5 +1,5 @@ using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Internal.UiDebug2.Utility; +using Dalamud.Interface.Internal.UiDebug.Utility; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -9,7 +9,7 @@ using static Dalamud.Utility.Util; using Vector2 = System.Numerics.Vector2; using Vector4 = System.Numerics.Vector4; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A tree for an that can be printed and browsed via ImGui. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Res.cs similarity index 97% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Res.cs index 086a41efc..3ff64fd24 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Res.cs @@ -4,7 +4,7 @@ using System.Runtime.InteropServices; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; -using Dalamud.Interface.Internal.UiDebug2.Utility; +using Dalamud.Interface.Internal.UiDebug.Utility; using Dalamud.Interface.Utility.Raii; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -13,14 +13,14 @@ using static Dalamud.Bindings.ImGui.ImGuiCol; using static Dalamud.Bindings.ImGui.ImGuiTreeNodeFlags; using static Dalamud.Interface.ColorHelpers; using static Dalamud.Interface.FontAwesomeIcon; -using static Dalamud.Interface.Internal.UiDebug2.Browsing.Events; -using static Dalamud.Interface.Internal.UiDebug2.ElementSelector; -using static Dalamud.Interface.Internal.UiDebug2.UiDebug2; -using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; +using static Dalamud.Interface.Internal.UiDebug.Browsing.Events; +using static Dalamud.Interface.Internal.UiDebug.ElementSelector; +using static Dalamud.Interface.Internal.UiDebug.UiDebug; +using static Dalamud.Interface.Internal.UiDebug.Utility.Gui; using static Dalamud.Utility.Util; using static FFXIVClientStructs.FFXIV.Component.GUI.NodeFlags; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A tree for an that can be printed and browsed via ImGui. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Text.cs similarity index 96% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Text.cs index 7ae0d8fca..74e14b683 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Text.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/NodeTree.Text.cs @@ -12,10 +12,10 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using Lumina.Text.ReadOnly; using static Dalamud.Interface.ColorHelpers; -using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; +using static Dalamud.Interface.Internal.UiDebug.Utility.Gui; using static Dalamud.Utility.Util; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A tree for an that can be printed and browsed via ImGui. diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.KeyGroupColumn.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/TimelineTree.KeyGroupColumn.cs similarity index 98% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.KeyGroupColumn.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/TimelineTree.KeyGroupColumn.cs index 71323088b..910762d97 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.KeyGroupColumn.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/TimelineTree.KeyGroupColumn.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Dalamud.Bindings.ImGui; -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// public readonly partial struct TimelineTree diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs b/Dalamud/Interface/Internal/UiDebug/Browsing/TimelineTree.cs similarity index 99% rename from Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs rename to Dalamud/Interface/Internal/UiDebug/Browsing/TimelineTree.cs index 10d3d9362..a4d7151c0 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Browsing/TimelineTree.cs +++ b/Dalamud/Interface/Internal/UiDebug/Browsing/TimelineTree.cs @@ -13,12 +13,12 @@ using static Dalamud.Bindings.ImGui.ImGuiTableColumnFlags; using static Dalamud.Bindings.ImGui.ImGuiTableFlags; using static Dalamud.Bindings.ImGui.ImGuiTreeNodeFlags; using static Dalamud.Interface.ColorHelpers; -using static Dalamud.Interface.Internal.UiDebug2.Utility.Gui; +using static Dalamud.Interface.Internal.UiDebug.Utility.Gui; using static Dalamud.Utility.Util; using static FFXIVClientStructs.FFXIV.Component.GUI.NodeType; // ReSharper disable SuggestBaseTypeForParameter -namespace Dalamud.Interface.Internal.UiDebug2.Browsing; +namespace Dalamud.Interface.Internal.UiDebug.Browsing; /// /// A struct allowing a node's animation timeline to be printed and browsed. diff --git a/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs b/Dalamud/Interface/Internal/UiDebug/ElementSelector.cs similarity index 95% rename from Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs rename to Dalamud/Interface/Internal/UiDebug/ElementSelector.cs index 46e0c1f8f..808ff25d7 100644 --- a/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs +++ b/Dalamud/Interface/Internal/UiDebug/ElementSelector.cs @@ -5,8 +5,8 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Interface.Components; -using Dalamud.Interface.Internal.UiDebug2.Browsing; -using Dalamud.Interface.Internal.UiDebug2.Utility; +using Dalamud.Interface.Internal.UiDebug.Browsing; +using Dalamud.Interface.Internal.UiDebug.Utility; using Dalamud.Interface.Utility.Raii; using FFXIVClientStructs.FFXIV.Component.GUI; @@ -16,7 +16,7 @@ using static System.Globalization.NumberFormatInfo; using static Dalamud.Bindings.ImGui.ImGuiCol; using static Dalamud.Bindings.ImGui.ImGuiWindowFlags; using static Dalamud.Interface.FontAwesomeIcon; -using static Dalamud.Interface.Internal.UiDebug2.UiDebug2; +using static Dalamud.Interface.Internal.UiDebug.UiDebug; using static Dalamud.Interface.UiBuilder; using static Dalamud.Interface.Utility.ImGuiHelpers; using static FFXIVClientStructs.FFXIV.Component.GUI.NodeFlags; @@ -25,7 +25,7 @@ using static FFXIVClientStructs.FFXIV.Component.GUI.NodeFlags; #pragma warning disable CS0659 -namespace Dalamud.Interface.Internal.UiDebug2; +namespace Dalamud.Interface.Internal.UiDebug; /// /// A tool that enables the user to select UI elements within the inspector by mousing over them onscreen. @@ -34,7 +34,7 @@ internal unsafe class ElementSelector : IDisposable { private const int UnitListCount = 18; - private readonly UiDebug2 uiDebug2; + private readonly UiDebug uiDebug; private string addressSearchInput = string.Empty; @@ -43,10 +43,10 @@ internal unsafe class ElementSelector : IDisposable /// /// Initializes a new instance of the class. /// - /// The instance of this Element Selector belongs to. - internal ElementSelector(UiDebug2 uiDebug2) + /// The instance of this Element Selector belongs to. + internal ElementSelector(UiDebug uiDebug) { - this.uiDebug2 = uiDebug2; + this.uiDebug = uiDebug; } /// @@ -181,7 +181,7 @@ internal unsafe class ElementSelector : IDisposable { this.Active = false; - this.uiDebug2.SelectedAddonName = a.Addon->NameString; + this.uiDebug.SelectedAddonName = a.Addon->NameString; var ptrList = new List { (nint)n.Node }; @@ -420,7 +420,7 @@ internal unsafe class ElementSelector : IDisposable var addon = unitManager->Entries[j].Value; if ((nint)addon == address || FindByAddress(addon, address)) { - this.uiDebug2.SelectedAddonName = addon->NameString; + this.uiDebug.SelectedAddonName = addon->NameString; return; } } diff --git a/Dalamud/Interface/Internal/UiDebug2/Popout.Addon.cs b/Dalamud/Interface/Internal/UiDebug/Popout.Addon.cs similarity index 93% rename from Dalamud/Interface/Internal/UiDebug2/Popout.Addon.cs rename to Dalamud/Interface/Internal/UiDebug/Popout.Addon.cs index 69fbc17fb..cc80a27c4 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Popout.Addon.cs +++ b/Dalamud/Interface/Internal/UiDebug/Popout.Addon.cs @@ -1,11 +1,11 @@ using System.Numerics; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Internal.UiDebug2.Browsing; +using Dalamud.Interface.Internal.UiDebug.Browsing; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; -namespace Dalamud.Interface.Internal.UiDebug2; +namespace Dalamud.Interface.Internal.UiDebug; /// /// A popout window for an . diff --git a/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs b/Dalamud/Interface/Internal/UiDebug/Popout.Node.cs similarity index 93% rename from Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs rename to Dalamud/Interface/Internal/UiDebug/Popout.Node.cs index de476983f..7d955f7f5 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Popout.Node.cs +++ b/Dalamud/Interface/Internal/UiDebug/Popout.Node.cs @@ -1,15 +1,15 @@ using System.Numerics; using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Internal.UiDebug2.Browsing; +using Dalamud.Interface.Internal.UiDebug.Browsing; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using FFXIVClientStructs.FFXIV.Component.GUI; -using static Dalamud.Interface.Internal.UiDebug2.UiDebug2; +using static Dalamud.Interface.Internal.UiDebug.UiDebug; -namespace Dalamud.Interface.Internal.UiDebug2; +namespace Dalamud.Interface.Internal.UiDebug; /// /// A popout window for a . diff --git a/Dalamud/Interface/Internal/UiDebug2/UiDebug2.Sidebar.cs b/Dalamud/Interface/Internal/UiDebug/UiDebug.Sidebar.cs similarity index 98% rename from Dalamud/Interface/Internal/UiDebug2/UiDebug2.Sidebar.cs rename to Dalamud/Interface/Internal/UiDebug/UiDebug.Sidebar.cs index 14da58d94..0a24d4572 100644 --- a/Dalamud/Interface/Internal/UiDebug2/UiDebug2.Sidebar.cs +++ b/Dalamud/Interface/Internal/UiDebug/UiDebug.Sidebar.cs @@ -12,10 +12,10 @@ using static System.StringComparison; using static Dalamud.Interface.FontAwesomeIcon; -namespace Dalamud.Interface.Internal.UiDebug2; +namespace Dalamud.Interface.Internal.UiDebug; -/// -internal unsafe partial class UiDebug2 +/// +internal unsafe partial class UiDebug { /// /// All unit lists to check for addons. diff --git a/Dalamud/Interface/Internal/UiDebug2/UiDebug2.cs b/Dalamud/Interface/Internal/UiDebug/UiDebug.cs similarity index 92% rename from Dalamud/Interface/Internal/UiDebug2/UiDebug2.cs rename to Dalamud/Interface/Internal/UiDebug/UiDebug.cs index 2aaef9256..bd7426466 100644 --- a/Dalamud/Interface/Internal/UiDebug2/UiDebug2.cs +++ b/Dalamud/Interface/Internal/UiDebug/UiDebug.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Dalamud.Bindings.ImGui; using Dalamud.Game.Gui; -using Dalamud.Interface.Internal.UiDebug2.Browsing; +using Dalamud.Interface.Internal.UiDebug.Browsing; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using Dalamud.Logging.Internal; @@ -12,7 +12,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI; using static Dalamud.Bindings.ImGui.ImGuiWindowFlags; -namespace Dalamud.Interface.Internal.UiDebug2; +namespace Dalamud.Interface.Internal.UiDebug; // Original version by aers https://github.com/aers/FFXIVUIDebug // Also incorporates features from Caraxi's fork https://github.com/Caraxi/SimpleTweaksPlugin/blob/main/Debugging/UIDebug.cs @@ -20,17 +20,17 @@ namespace Dalamud.Interface.Internal.UiDebug2; /// /// A tool for browsing the contents and structure of UI elements. /// -internal partial class UiDebug2 : IDisposable +internal partial class UiDebug : IDisposable { /// - internal static readonly ModuleLog Log = ModuleLog.Create(); + internal static readonly ModuleLog Log = ModuleLog.Create(); private readonly ElementSelector elementSelector; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - internal UiDebug2() + internal UiDebug() { this.elementSelector = new(this); } diff --git a/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs b/Dalamud/Interface/Internal/UiDebug/Utility/Gui.cs similarity index 97% rename from Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs rename to Dalamud/Interface/Internal/UiDebug/Utility/Gui.cs index adfbfa81c..2c02fd793 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs +++ b/Dalamud/Interface/Internal/UiDebug/Utility/Gui.cs @@ -9,10 +9,10 @@ using FFXIVClientStructs.FFXIV.Client.Graphics; using static Dalamud.Bindings.ImGui.ImGuiCol; using static Dalamud.Interface.ColorHelpers; -namespace Dalamud.Interface.Internal.UiDebug2.Utility; +namespace Dalamud.Interface.Internal.UiDebug.Utility; /// -/// Miscellaneous ImGui tools used by . +/// Miscellaneous ImGui tools used by . /// internal static class Gui { diff --git a/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs b/Dalamud/Interface/Internal/UiDebug/Utility/NodeBounds.cs similarity index 99% rename from Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs rename to Dalamud/Interface/Internal/UiDebug/Utility/NodeBounds.cs index 20feb903f..414d49cf5 100644 --- a/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs +++ b/Dalamud/Interface/Internal/UiDebug/Utility/NodeBounds.cs @@ -11,7 +11,7 @@ using static System.MathF; using static Dalamud.Interface.ColorHelpers; -namespace Dalamud.Interface.Internal.UiDebug2.Utility; +namespace Dalamud.Interface.Internal.UiDebug.Utility; /// /// A struct representing the perimeter of an , accounting for all transformations. diff --git a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs index 444b923ab..64de5e87d 100644 --- a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs @@ -21,7 +21,6 @@ internal class DataWindow : Window, IDisposable private readonly IDataWindowWidget[] modules = [ new AddonInspectorWidget(), - new AddonInspectorWidget2(), new AddonLifecycleWidget(), new AddonWidget(), new AddressesWidget(), diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget.cs index c8a747239..95a5616b1 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget.cs @@ -5,8 +5,8 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class AddonInspectorWidget : IDataWindowWidget { - private UiDebug? addonInspector; - + private UiDebug.UiDebug? addonInspector; + /// public string[]? CommandShortcuts { get; init; } = ["ai", "addoninspector"]; @@ -19,7 +19,7 @@ internal class AddonInspectorWidget : IDataWindowWidget /// public void Load() { - this.addonInspector = new UiDebug(); + this.addonInspector = new UiDebug.UiDebug(); if (this.addonInspector is not null) { diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget2.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget2.cs deleted file mode 100644 index 6cd6ecb0b..000000000 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonInspectorWidget2.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace Dalamud.Interface.Internal.Windows.Data.Widgets; - -/// -/// Widget for displaying addon inspector. -/// -internal class AddonInspectorWidget2 : IDataWindowWidget -{ - private UiDebug2.UiDebug2? addonInspector2; - - /// - public string[]? CommandShortcuts { get; init; } = ["ai2", "addoninspector2"]; - - /// - public string DisplayName { get; init; } = "Addon Inspector v2 (Testing)"; - - /// - public bool Ready { get; set; } - - /// - public void Load() - { - this.addonInspector2 = new UiDebug2.UiDebug2(); - - if (this.addonInspector2 is not null) - { - this.Ready = true; - } - } - - /// - public void Draw() - { - this.addonInspector2?.Draw(); - } -} diff --git a/Dalamud/Plugin/Services/ITextureProvider.cs b/Dalamud/Plugin/Services/ITextureProvider.cs index dc0522aa8..a4d1dcbd2 100644 --- a/Dalamud/Plugin/Services/ITextureProvider.cs +++ b/Dalamud/Plugin/Services/ITextureProvider.cs @@ -322,7 +322,7 @@ public interface ITextureProvider : IDalamudService /// Whether to leave non-disposed when the returned /// completes. /// Address of the new . - /// See PrintTextureInfo in for an example + /// See PrintTextureInfo in for an example /// of replacing the texture of an image node. /// /// If the returned kernel texture is to be destroyed, call the fourth function in its vtable, by calling From 8f8f4faa12dc0ea028546cc60665159ac62b737b Mon Sep 17 00:00:00 2001 From: Infi Date: Mon, 26 Jan 2026 04:21:33 +0100 Subject: [PATCH 61/99] Apply ImRaii to Widgets Part 2 (#2567) * Apply ImRaii to multiple widgets * Apply ImRaii to leftover widgets --- .../Windows/Data/Widgets/AddonWidget.cs | 2 +- .../Windows/Data/Widgets/AddressesWidget.cs | 17 ++- .../Windows/Data/Widgets/AetherytesWidget.cs | 8 +- .../Data/Widgets/AtkArrayDataBrowserWidget.cs | 27 ++-- .../Windows/Data/Widgets/BuddyListWidget.cs | 111 ++++++++-------- .../Windows/Data/Widgets/CommandWidget.cs | 8 +- .../Data/Widgets/ConfigurationWidget.cs | 4 +- .../Windows/Data/Widgets/DataShareWidget.cs | 124 ++++++++---------- .../Windows/Data/Widgets/FateTableWidget.cs | 13 +- .../Windows/Data/Widgets/FlyTextWidget.cs | 15 ++- .../Widgets/GamePrebakedFontsTestWidget.cs | 6 +- .../Windows/Data/Widgets/GamepadWidget.cs | 20 +-- .../Windows/Data/Widgets/GaugeWidget.cs | 5 +- .../Windows/Data/Widgets/HookWidget.cs | 114 ++++++++-------- .../Windows/Data/Widgets/IconBrowserWidget.cs | 63 ++++----- .../Windows/Data/Widgets/ImGuiWidget.cs | 45 ++----- .../Windows/Data/Widgets/InventoryWidget.cs | 46 +++---- .../Windows/Data/Widgets/KeyStateWidget.cs | 11 +- .../Windows/Data/Widgets/MarketBoardWidget.cs | 74 +++++------ .../Data/Widgets/NetworkMonitorWidget.cs | 2 +- .../Data/Widgets/NounProcessorWidget.cs | 5 +- .../Windows/Data/Widgets/ObjectTableWidget.cs | 105 +++++++-------- .../Windows/Data/Widgets/PartyListWidget.cs | 8 +- .../Data/Widgets/SeStringCreatorWidget.cs | 42 +++--- .../Windows/Data/Widgets/ServicesWidget.cs | 20 +-- 25 files changed, 411 insertions(+), 484 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonWidget.cs index c0f923fc7..85ccd471d 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddonWidget.cs @@ -8,7 +8,7 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// /// Widget for displaying Addon Data. /// -internal unsafe class AddonWidget : IDataWindowWidget +internal class AddonWidget : IDataWindowWidget { private string inputAddonName = string.Empty; private int inputAddonIndex; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddressesWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddressesWidget.cs index 06c7ea393..6a4f2c9ab 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AddressesWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AddressesWidget.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Dalamud.Bindings.ImGui; using Dalamud.Game; +using Dalamud.Interface.Utility.Raii; using Dalamud.Utility; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -46,22 +47,24 @@ internal class AddressesWidget : IDataWindowWidget } } - ImGui.Text($"Result: {this.sigResult.ToInt64():X}"); + ImGui.AlignTextToFramePadding(); + ImGui.Text($"Result: {this.sigResult:X}"); ImGui.SameLine(); - if (ImGui.Button($"C##{this.sigResult.ToInt64():X}")) - ImGui.SetClipboardText(this.sigResult.ToInt64().ToString("X")); + if (ImGui.Button($"C##{this.sigResult:X}")) + ImGui.SetClipboardText($"{this.sigResult:X}"); foreach (var debugScannedValue in BaseAddressResolver.DebugScannedValues) { ImGui.Text($"{debugScannedValue.Key}"); foreach (var valueTuple in debugScannedValue.Value) { - ImGui.Text( - $" {valueTuple.ClassName} - {Util.DescribeAddress(valueTuple.Address)}"); + using var indent = ImRaii.PushIndent(10.0f); + ImGui.AlignTextToFramePadding(); + ImGui.Text($"{valueTuple.ClassName} - {Util.DescribeAddress(valueTuple.Address)}"); ImGui.SameLine(); - if (ImGui.Button($"C##{valueTuple.Address.ToInt64():X}")) - ImGui.SetClipboardText(valueTuple.Address.ToInt64().ToString("X")); + if (ImGui.Button($"C##{valueTuple.Address:X}")) + ImGui.SetClipboardText($"{valueTuple.Address:X}"); } } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs index f414a9423..68ba93b36 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AetherytesWidget.cs @@ -1,5 +1,6 @@ using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Aetherytes; +using Dalamud.Interface.Utility.Raii; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -8,6 +9,8 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class AetherytesWidget : IDataWindowWidget { + private const ImGuiTableFlags TableFlags = ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders; + /// public bool Ready { get; set; } @@ -26,7 +29,8 @@ internal class AetherytesWidget : IDataWindowWidget /// public void Draw() { - if (!ImGui.BeginTable("##aetheryteTable"u8, 11, ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders)) + using var table = ImRaii.Table("##aetheryteTable"u8, 11, TableFlags); + if (!table.Success) return; ImGui.TableSetupScrollFreeze(0, 1); @@ -84,7 +88,5 @@ internal class AetherytesWidget : IDataWindowWidget ImGui.TableNextColumn(); // Apartment ImGui.Text($"{info.IsApartment}"); } - - ImGui.EndTable(); } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/AtkArrayDataBrowserWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/AtkArrayDataBrowserWidget.cs index 03f5ab32e..6f9bbdb1b 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/AtkArrayDataBrowserWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/AtkArrayDataBrowserWidget.cs @@ -25,10 +25,10 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget private int selectedExtendArray; private string searchTerm = string.Empty; - private bool hideUnsetStringArrayEntries = false; - private bool hideUnsetExtendArrayEntries = false; - private bool showTextAddress = false; - private bool showMacroString = false; + private bool hideUnsetStringArrayEntries; + private bool hideUnsetExtendArrayEntries; + private bool showTextAddress; + private bool showMacroString; /// public bool Ready { get; set; } @@ -155,17 +155,14 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget if (ImGui.IsItemHovered()) { using var tooltip = ImRaii.Tooltip(); - if (tooltip) + + var raptureAtkUnitManager = RaptureAtkUnitManager.Instance(); + for (var j = 0; j < array->SubscribedAddonsCount; j++) { - var raptureAtkUnitManager = RaptureAtkUnitManager.Instance(); + if (array->SubscribedAddons[j] == 0) + continue; - for (var j = 0; j < array->SubscribedAddonsCount; j++) - { - if (array->SubscribedAddons[j] == 0) - continue; - - ImGui.Text(raptureAtkUnitManager->GetAddonById(array->SubscribedAddons[j])->NameString); - } + ImGui.Text(raptureAtkUnitManager->GetAddonById(array->SubscribedAddons[j])->NameString); } } } @@ -244,9 +241,9 @@ internal unsafe class AtkArrayDataBrowserWidget : IDataWindowWidget var atkArrayDataHolder = RaptureAtkModule.Instance()->AtkArrayDataHolder; - using (var sidebarchild = ImRaii.Child("StringArraySidebar"u8, new Vector2(300, -1), false, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoSavedSettings)) + using (var sidebarChild = ImRaii.Child("StringArraySidebar"u8, new Vector2(300, -1), false, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoSavedSettings)) { - if (sidebarchild) + if (sidebarChild) { ImGui.SetNextItemWidth(-1); ImGui.InputTextWithHint("##TextSearch"u8, "Search..."u8, ref this.searchTerm, 256, ImGuiInputTextFlags.AutoSelectAll); diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/BuddyListWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/BuddyListWidget.cs index 10efdbae1..bbef5fee3 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/BuddyListWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/BuddyListWidget.cs @@ -32,18 +32,65 @@ internal class BuddyListWidget : IDataWindowWidget var buddyList = Service.Get(); ImGui.Checkbox("Resolve GameData"u8, ref this.resolveGameData); + + var companionBuddy = buddyList.CompanionBuddy; + if (companionBuddy == null) { - var member = buddyList.CompanionBuddy; - if (member == null) + ImGui.Text("[Companion] null"u8); + } + else + { + ImGui.Text($"[Companion] {companionBuddy.Address:X} - {companionBuddy.EntityId} - {companionBuddy.DataID}"); + if (this.resolveGameData) { - ImGui.Text("[Companion] null"u8); + var gameObject = companionBuddy.GameObject; + if (gameObject == null) + { + ImGui.Text("GameObject was null"u8); + } + else + { + Util.PrintGameObject(gameObject, "-", this.resolveGameData); + } } - else + } + + var petBuddy = buddyList.PetBuddy; + if (petBuddy == null) + { + ImGui.Text("[Pet] null"u8); + } + else + { + ImGui.Text($"[Pet] {petBuddy.Address:X} - {petBuddy.EntityId} - {petBuddy.DataID}"); + if (this.resolveGameData) { - ImGui.Text($"[Companion] {member.Address.ToInt64():X} - {member.EntityId} - {member.DataID}"); + var gameObject = petBuddy.GameObject; + if (gameObject == null) + { + ImGui.Text("GameObject was null"u8); + } + else + { + Util.PrintGameObject(gameObject, "-", this.resolveGameData); + } + } + } + + var count = buddyList.Length; + if (count == 0) + { + ImGui.Text("[BattleBuddy] None present"u8); + } + else + { + for (var i = 0; i < count; i++) + { + var member = buddyList[i]; + ImGui.Text($"[BattleBuddy] [{i}] {member?.Address ?? 0:X} - {member?.EntityId ?? 0} - {member?.DataID ?? 0}"); if (this.resolveGameData) { - var gameObject = member.GameObject; + var gameObject = member?.GameObject; if (gameObject == null) { ImGui.Text("GameObject was null"u8); @@ -55,57 +102,5 @@ internal class BuddyListWidget : IDataWindowWidget } } } - - { - var member = buddyList.PetBuddy; - if (member == null) - { - ImGui.Text("[Pet] null"u8); - } - else - { - ImGui.Text($"[Pet] {member.Address.ToInt64():X} - {member.EntityId} - {member.DataID}"); - if (this.resolveGameData) - { - var gameObject = member.GameObject; - if (gameObject == null) - { - ImGui.Text("GameObject was null"u8); - } - else - { - Util.PrintGameObject(gameObject, "-", this.resolveGameData); - } - } - } - } - - { - var count = buddyList.Length; - if (count == 0) - { - ImGui.Text("[BattleBuddy] None present"u8); - } - else - { - for (var i = 0; i < count; i++) - { - var member = buddyList[i]; - ImGui.Text($"[BattleBuddy] [{i}] {member?.Address.ToInt64():X} - {member?.EntityId} - {member?.DataID}"); - if (this.resolveGameData) - { - var gameObject = member?.GameObject; - if (gameObject == null) - { - ImGui.Text("GameObject was null"u8); - } - else - { - Util.PrintGameObject(gameObject, "-", this.resolveGameData); - } - } - } - } - } } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/CommandWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/CommandWidget.cs index 1082bf6ca..e1b06aaf3 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/CommandWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/CommandWidget.cs @@ -11,6 +11,10 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class CommandWidget : IDataWindowWidget { + private const ImGuiTableFlags TableFlags = ImGuiTableFlags.ScrollY | ImGuiTableFlags.Borders | + ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.Sortable | + ImGuiTableFlags.SortTristate; + /// public string[]? CommandShortcuts { get; init; } = ["command"]; @@ -31,9 +35,7 @@ internal class CommandWidget : IDataWindowWidget { var commandManager = Service.Get(); - var tableFlags = ImGuiTableFlags.ScrollY | ImGuiTableFlags.Borders | ImGuiTableFlags.SizingStretchProp | - ImGuiTableFlags.Sortable | ImGuiTableFlags.SortTristate; - using var table = ImRaii.Table("CommandList"u8, 4, tableFlags); + using var table = ImRaii.Table("CommandList"u8, 4, TableFlags); if (table) { ImGui.TableSetupScrollFreeze(0, 1); diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ConfigurationWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ConfigurationWidget.cs index c6a3477ae..df5aeab56 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ConfigurationWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ConfigurationWidget.cs @@ -10,9 +10,9 @@ internal class ConfigurationWidget : IDataWindowWidget { /// public string[]? CommandShortcuts { get; init; } = ["config", "configuration"]; - + /// - public string DisplayName { get; init; } = "Configuration"; + public string DisplayName { get; init; } = "Configuration"; /// public bool Ready { get; set; } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/DataShareWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/DataShareWidget.cs index 8c9774840..73e9d18f8 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/DataShareWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/DataShareWidget.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; using System.Reflection; @@ -21,13 +20,9 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// /// Widget for displaying plugin data share modules. /// -[SuppressMessage( - "StyleCop.CSharp.LayoutRules", - "SA1519:Braces should not be omitted from multi-line child statement", - Justification = "Multiple fixed blocks")] internal class DataShareWidget : IDataWindowWidget { - private const ImGuiTabItemFlags NoCloseButton = (ImGuiTabItemFlags)(1 << 20); + private const ImGuiTabItemFlags NoCloseButton = (ImGuiTabItemFlags)ImGuiTabItemFlagsPrivate.NoCloseButton; private readonly List<(string Name, byte[]? Data)> dataView = []; private int nextTab = -1; @@ -50,42 +45,37 @@ internal class DataShareWidget : IDataWindowWidget } /// - public unsafe void Draw() + public void Draw() { using var tabbar = ImRaii.TabBar("##tabbar"u8); if (!tabbar.Success) return; var d = true; - using (var tabitem = ImRaii.TabItem( - "Data Share##tabbar-datashare"u8, - ref d, - NoCloseButton | (this.nextTab == 0 ? ImGuiTabItemFlags.SetSelected : 0))) + using (var tabItem = ImRaii.TabItem("Data Share##tabbar-datashare"u8, ref d, NoCloseButton | (this.nextTab == 0 ? ImGuiTabItemFlags.SetSelected : 0))) { - if (tabitem.Success) + if (tabItem.Success) this.DrawDataShare(); } - using (var tabitem = ImRaii.TabItem( - "Call Gate##tabbar-callgate"u8, - ref d, - NoCloseButton | (this.nextTab == 1 ? ImGuiTabItemFlags.SetSelected : 0))) + using (var tabItem = ImRaii.TabItem("Call Gate##tabbar-callgate"u8, ref d, NoCloseButton | (this.nextTab == 1 ? ImGuiTabItemFlags.SetSelected : 0))) { - if (tabitem.Success) + if (tabItem.Success) this.DrawCallGate(); } for (var i = 0; i < this.dataView.Count; i++) { using var idpush = ImRaii.PushId($"##tabbar-data-{i}"); + var (name, data) = this.dataView[i]; d = true; - using var tabitem = ImRaii.TabItem( - name, - ref d, - this.nextTab == 2 + i ? ImGuiTabItemFlags.SetSelected : 0); + + using var tabitem = ImRaii.TabItem(name, ref d, this.nextTab == 2 + i ? ImGuiTabItemFlags.SetSelected : 0); + if (!d) this.dataView.RemoveAt(i--); + if (!tabitem.Success) continue; @@ -123,11 +113,7 @@ internal class DataShareWidget : IDataWindowWidget if (ImGui.Button("Copy"u8)) ImGui.SetClipboardText(data); - ImGui.InputTextMultiline( - "text"u8, - data, - ImGui.GetContentRegionAvail(), - ImGuiInputTextFlags.ReadOnly); + ImGui.InputTextMultiline("text"u8, data, ImGui.GetContentRegionAvail(), ImGuiInputTextFlags.ReadOnly); } this.nextTab = -1; @@ -142,8 +128,10 @@ internal class DataShareWidget : IDataWindowWidget sb.Append(ReprType(mi.DeclaringType)) .Append("::") .Append(mi.Name); + if (!withParams) return sb.ToString(); + sb.Append('('); var parfirst = true; foreach (var par in mi.GetParameters()) @@ -152,6 +140,7 @@ internal class DataShareWidget : IDataWindowWidget sb.Append(", "); else parfirst = false; + sb.AppendLine() .Append('\t') .Append(ReprType(par.ParameterType)) @@ -161,9 +150,11 @@ internal class DataShareWidget : IDataWindowWidget if (!parfirst) sb.AppendLine(); + sb.Append(')'); if (mi.ReturnType != typeof(void)) sb.Append(" -> ").Append(ReprType(mi.ReturnType)); + return sb.ToString(); static string WithoutGeneric(string s) @@ -172,8 +163,7 @@ internal class DataShareWidget : IDataWindowWidget return i != -1 ? s[..i] : s; } - static string ReprType(Type? t) => - t switch + static string ReprType(Type? t) => t switch { null => "null", _ when t == typeof(string) => "string", @@ -215,18 +205,19 @@ internal class DataShareWidget : IDataWindowWidget var offset = ImGui.GetCursorScreenPos() + new Vector2(0, framepad ? ImGui.GetStyle().FramePadding.Y : 0); if (framepad) ImGui.AlignTextToFramePadding(); + ImGui.Text(s); if (ImGui.IsItemHovered()) { ImGui.SetNextWindowPos(offset - ImGui.GetStyle().WindowPadding); var vp = ImGui.GetWindowViewport(); var wrx = (vp.WorkPos.X + vp.WorkSize.X) - offset.X; + ImGui.SetNextWindowSizeConstraints(Vector2.One, new(wrx, float.MaxValue)); using (ImRaii.Tooltip()) { - ImGui.PushTextWrapPos(wrx); + using var pushedWrap = ImRaii.TextWrapPos(wrx); ImGui.TextWrapped(tooltip?.Invoke() ?? s); - ImGui.PopTextWrapPos(); } } @@ -247,6 +238,9 @@ internal class DataShareWidget : IDataWindowWidget callGate.PurgeEmptyGates(); using var table = ImRaii.Table("##callgate-table"u8, 5); + if (!table.Success) + return; + ImGui.TableSetupColumn("Name"u8, ImGuiTableColumnFlags.DefaultSort); ImGui.TableSetupColumn("Action"u8); ImGui.TableSetupColumn("Func"u8); @@ -268,12 +262,8 @@ internal class DataShareWidget : IDataWindowWidget { ImGui.TableNextRow(); this.DrawTextCell(item.Name); - this.DrawTextCell( - ReprMethod(item.Action?.Method, false), - () => ReprMethod(item.Action?.Method, true)); - this.DrawTextCell( - ReprMethod(item.Func?.Method, false), - () => ReprMethod(item.Func?.Method, true)); + this.DrawTextCell(ReprMethod(item.Action?.Method, false), () => ReprMethod(item.Action?.Method, true)); + this.DrawTextCell(ReprMethod(item.Func?.Method, false), () => ReprMethod(item.Func?.Method, true)); if (subs.Count == 0) { this.DrawTextCell("0"); @@ -288,47 +278,43 @@ internal class DataShareWidget : IDataWindowWidget private void DrawDataShare() { - if (!ImGui.BeginTable("###DataShareTable"u8, 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg)) + using var table = ImRaii.Table("###DataShareTable"u8, 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); + if (!table.Success) return; - try + ImGui.TableSetupColumn("Shared Tag"u8); + ImGui.TableSetupColumn("Show"u8); + ImGui.TableSetupColumn("Creator Assembly"u8); + ImGui.TableSetupColumn("#"u8, ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale); + ImGui.TableSetupColumn("Consumers"u8); + ImGui.TableHeadersRow(); + + foreach (var share in Service.Get().GetAllShares()) { - ImGui.TableSetupColumn("Shared Tag"u8); - ImGui.TableSetupColumn("Show"u8); - ImGui.TableSetupColumn("Creator Assembly"u8); - ImGui.TableSetupColumn("#"u8, ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale); - ImGui.TableSetupColumn("Consumers"u8); - ImGui.TableHeadersRow(); - foreach (var share in Service.Get().GetAllShares()) + ImGui.TableNextRow(); + this.DrawTextCell(share.Tag, null, true); + + ImGui.TableNextColumn(); + if (ImGui.Button($"Show##datasharetable-show-{share.Tag}")) { - ImGui.TableNextRow(); - this.DrawTextCell(share.Tag, null, true); - - ImGui.TableNextColumn(); - if (ImGui.Button($"Show##datasharetable-show-{share.Tag}")) + var index = 0; + for (; index < this.dataView.Count; index++) { - var index = 0; - for (; index < this.dataView.Count; index++) - { - if (this.dataView[index].Name == share.Tag) - break; - } - - if (index == this.dataView.Count) - this.dataView.Add((share.Tag, null)); - else - this.dataView[index] = (share.Tag, null); - this.nextTab = 2 + index; + if (this.dataView[index].Name == share.Tag) + break; } - this.DrawTextCell(share.CreatorAssembly, null, true); - this.DrawTextCell(share.Users.Length.ToString(), null, true); - this.DrawTextCell(string.Join(", ", share.Users), null, true); + if (index == this.dataView.Count) + this.dataView.Add((share.Tag, null)); + else + this.dataView[index] = (share.Tag, null); + + this.nextTab = 2 + index; } - } - finally - { - ImGui.EndTable(); + + this.DrawTextCell(share.CreatorAssembly, null, true); + this.DrawTextCell(share.Users.Length.ToString(), null, true); + this.DrawTextCell(string.Join(", ", share.Users), null, true); } } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/FateTableWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/FateTableWidget.cs index e241f157d..b2f4bf70f 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/FateTableWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/FateTableWidget.cs @@ -10,6 +10,9 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class FateTableWidget : IDataWindowWidget { + private const ImGuiTableFlags TableFlags = ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg | + ImGuiTableFlags.Borders | ImGuiTableFlags.NoSavedSettings; + /// public string[]? CommandShortcuts { get; init; } = ["fate", "fatetable"]; @@ -37,7 +40,7 @@ internal class FateTableWidget : IDataWindowWidget return; } - using var table = ImRaii.Table("FateTable"u8, 13, ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.NoSavedSettings); + using var table = ImRaii.Table("FateTable"u8, 13, TableFlags); if (!table) return; ImGui.TableSetupColumn("Index"u8, ImGuiTableColumnFlags.WidthFixed, 40); @@ -97,11 +100,11 @@ internal class FateTableWidget : IDataWindowWidget if (ImGui.IsItemHovered()) { ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); - ImGui.BeginTooltip(); + + using var tooltip = ImRaii.Tooltip(); ImGui.Text("Click to copy IconId"u8); ImGui.Text($"ID: {fate.IconId} – Size: {texture.Width}x{texture.Height}"); ImGui.Image(texture.Handle, new(texture.Width, texture.Height)); - ImGui.EndTooltip(); } if (ImGui.IsItemClicked()) @@ -122,11 +125,11 @@ internal class FateTableWidget : IDataWindowWidget if (ImGui.IsItemHovered()) { ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); - ImGui.BeginTooltip(); + + using var tooltip = ImRaii.Tooltip(); ImGui.Text("Click to copy MapIconId"u8); ImGui.Text($"ID: {fate.MapIconId} – Size: {texture.Width}x{texture.Height}"); ImGui.Image(texture.Handle, new(texture.Width, texture.Height)); - ImGui.EndTooltip(); } if (ImGui.IsItemClicked()) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/FlyTextWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/FlyTextWidget.cs index 7910daaec..00e424551 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/FlyTextWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/FlyTextWidget.cs @@ -3,6 +3,7 @@ using System.Numerics; using Dalamud.Bindings.ImGui; using Dalamud.Game.Gui.FlyText; +using Dalamud.Interface.Utility.Raii; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -39,18 +40,18 @@ internal class FlyTextWidget : IDataWindowWidget /// public void Draw() { - if (ImGui.BeginCombo("Kind"u8, $"{this.flyKind} ({(int)this.flyKind})")) + using (var combo = ImRaii.Combo("Kind"u8, $"{this.flyKind} ({(int)this.flyKind})")) { - var values = Enum.GetValues().Distinct(); - foreach (var value in values) + if (combo.Success) { - if (ImGui.Selectable($"{value} ({(int)value})")) + foreach (var value in Enum.GetValues().Distinct()) { - this.flyKind = value; + if (ImGui.Selectable($"{value} ({(int)value})")) + { + this.flyKind = value; + } } } - - ImGui.EndCombo(); } ImGui.InputText("Text1"u8, ref this.flyText1, 200); diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs index 32ad076db..0c0289bd0 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamePrebakedFontsTestWidget.cs @@ -13,6 +13,7 @@ using Dalamud.Interface.ImGuiFontChooserDialog; using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.ManagedFontAtlas.Internals; using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; using Dalamud.Utility; using Serilog; @@ -248,7 +249,8 @@ internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable { ImGui.Text($"{gfs.SizePt}pt"); ImGui.SameLine(offsetX); - ImGui.PushTextWrapPos(this.useWordWrap ? 0f : -1f); + + using var pushedWrap = ImRaii.TextWrapPos(this.useWordWrap ? 0f : -1f); try { if (handle.Value.LoadException is { } exc) @@ -263,6 +265,7 @@ internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable { if (!this.atlasScaleMode) ImGui.SetWindowFontScale(1 / ImGuiHelpers.GlobalScale); + if (counter++ % 2 == 0) { using var pushPop = handle.Value.Push(); @@ -279,7 +282,6 @@ internal class GamePrebakedFontsTestWidget : IDataWindowWidget, IDisposable finally { ImGui.SetWindowFontScale(1); - ImGui.PopTextWrapPos(); } } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs index ed1a4da5b..12aa4c4ae 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs @@ -39,22 +39,10 @@ internal class GamepadWidget : IDataWindowWidget ImGui.SetClipboardText($"{Util.DescribeAddress(gamepadState.GamepadInputAddress)}"); #endif - this.DrawHelper( - "Buttons Raw", - (uint)gamepadState.ButtonsRaw, - gamepadState.Raw); - this.DrawHelper( - "Buttons Pressed", - (uint)gamepadState.ButtonsPressed, - gamepadState.Pressed); - this.DrawHelper( - "Buttons Repeat", - (uint)gamepadState.ButtonsRepeat, - gamepadState.Repeat); - this.DrawHelper( - "Buttons Released", - (uint)gamepadState.ButtonsReleased, - gamepadState.Released); + this.DrawHelper("Buttons Raw", (uint)gamepadState.ButtonsRaw, gamepadState.Raw); + this.DrawHelper("Buttons Pressed", (uint)gamepadState.ButtonsPressed, gamepadState.Pressed); + this.DrawHelper("Buttons Repeat", (uint)gamepadState.ButtonsRepeat, gamepadState.Repeat); + this.DrawHelper("Buttons Released", (uint)gamepadState.ButtonsReleased, gamepadState.Released); ImGui.Text($"LeftStick {gamepadState.LeftStick}"); ImGui.Text($"RightStick {gamepadState.RightStick}"); } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs index 09bd29851..74403a32b 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs @@ -39,8 +39,7 @@ internal class GaugeWidget : IDataWindowWidget return; } - var jobID = player.ClassJob.RowId; - JobGaugeBase? gauge = jobID switch + JobGaugeBase? gauge = player.ClassJob.RowId switch { 19 => jobGauges.Get(), 20 => jobGauges.Get(), @@ -63,7 +62,7 @@ internal class GaugeWidget : IDataWindowWidget 40 => jobGauges.Get(), 41 => jobGauges.Get(), 42 => jobGauges.Get(), - _ => null, + _ => null }; if (gauge == null) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs index ad06e12fd..fd27996ed 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; using Dalamud.Bindings.ImGui; using Dalamud.Game; using Dalamud.Hooking; - +using Dalamud.Interface.Utility.Raii; using FFXIVClientStructs.FFXIV.Component.GUI; using Serilog; @@ -26,12 +26,12 @@ internal unsafe class HookWidget : IDataWindowWidget private Hook? messageBoxMinHook; private bool hookUseMinHook; - private int hookStressTestCount = 0; + private int hookStressTestCount; private int hookStressTestMax = 1000; private int hookStressTestWait = 100; private int hookStressTestMaxDegreeOfParallelism = 10; private StressTestHookTarget hookStressTestHookTarget = StressTestHookTarget.Random; - private bool hookStressTestRunning = false; + private bool hookStressTestRunning; private MessageBoxWDelegate? messageBoxWOriginal; private AddonFinalizeDelegate? addonFinalizeOriginal; @@ -50,7 +50,7 @@ internal unsafe class HookWidget : IDataWindowWidget { MessageBoxW, AddonFinalize, - Random, + Random } /// @@ -106,67 +106,68 @@ internal unsafe class HookWidget : IDataWindowWidget ImGui.Separator(); - ImGui.BeginDisabled(this.hookStressTestRunning); - ImGui.Text("Stress Test"u8); - - if (ImGui.InputInt("Max"u8, ref this.hookStressTestMax)) - this.hookStressTestCount = 0; - - ImGui.InputInt("Wait (ms)"u8, ref this.hookStressTestWait); - ImGui.InputInt("Max Degree of Parallelism"u8, ref this.hookStressTestMaxDegreeOfParallelism); - - if (ImGui.BeginCombo("Target"u8, HookTargetToString(this.hookStressTestHookTarget))) + using (ImRaii.Disabled(this.hookStressTestRunning)) { - foreach (var target in Enum.GetValues()) + ImGui.Text("Stress Test"u8); + + if (ImGui.InputInt("Max"u8, ref this.hookStressTestMax)) + this.hookStressTestCount = 0; + + ImGui.InputInt("Wait (ms)"u8, ref this.hookStressTestWait); + ImGui.InputInt("Max Degree of Parallelism"u8, ref this.hookStressTestMaxDegreeOfParallelism); + + using (var combo = ImRaii.Combo("Target"u8, HookTargetToString(this.hookStressTestHookTarget))) { - if (ImGui.Selectable(HookTargetToString(target), this.hookStressTestHookTarget == target)) - this.hookStressTestHookTarget = target; + if (combo.Success) + { + foreach (var target in Enum.GetValues()) + { + if (ImGui.Selectable(HookTargetToString(target), this.hookStressTestHookTarget == target)) + this.hookStressTestHookTarget = target; + } + } } - ImGui.EndCombo(); - } - - if (ImGui.Button("Stress Test"u8)) - { - Task.Run(() => + if (ImGui.Button("Stress Test"u8)) { - this.hookStressTestRunning = true; - this.hookStressTestCount = 0; - Parallel.For( - 0, - this.hookStressTestMax, - new ParallelOptions + Task.Run(() => + { + this.hookStressTestRunning = true; + this.hookStressTestCount = 0; + Parallel.For( + 0, + this.hookStressTestMax, + new ParallelOptions + { + MaxDegreeOfParallelism = this.hookStressTestMaxDegreeOfParallelism, + }, + _ => + { + this.hookStressTestList.Add(this.HookTarget(this.hookStressTestHookTarget)); + this.hookStressTestCount++; + Thread.Sleep(this.hookStressTestWait); + }); + }).ContinueWith(t => + { + if (t.IsFaulted) { - MaxDegreeOfParallelism = this.hookStressTestMaxDegreeOfParallelism, - }, - _ => + Log.Error(t.Exception, "Stress test failed"); + } + else { - this.hookStressTestList.Add(this.HookTarget(this.hookStressTestHookTarget)); - this.hookStressTestCount++; - Thread.Sleep(this.hookStressTestWait); + Log.Information("Stress test completed"); + } + + this.hookStressTestRunning = false; + this.hookStressTestList.ForEach(hook => + { + hook.Dispose(); }); - }).ContinueWith(t => - { - if (t.IsFaulted) - { - Log.Error(t.Exception, "Stress test failed"); - } - else - { - Log.Information("Stress test completed"); - } - - this.hookStressTestRunning = false; - this.hookStressTestList.ForEach(hook => - { - hook.Dispose(); + this.hookStressTestList.Clear(); }); - this.hookStressTestList.Clear(); - }); + } } - ImGui.EndDisabled(); - ImGui.Text("Status: " + (this.hookStressTestRunning ? "Running" : "Idle")); ImGui.ProgressBar(this.hookStressTestCount / (float)this.hookStressTestMax, new System.Numerics.Vector2(0, 0), $"{this.hookStressTestCount}/{this.hookStressTestMax}"); } @@ -206,11 +207,6 @@ internal unsafe class HookWidget : IDataWindowWidget this.addonFinalizeOriginal!(unitManager, atkUnitBase); } - private void OnAddonUpdate(AtkUnitBase* thisPtr, float delta) - { - Log.Information("OnAddonUpdate"); - } - private IDalamudHook HookMessageBoxW() { var hook = Hook.FromSymbol( diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs index 77ca7ec2b..670b83f67 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/IconBrowserWidget.cs @@ -8,6 +8,7 @@ using Dalamud.Interface.Textures.Internal; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Internal; +using Dalamud.Interface.Utility.Raii; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -62,6 +63,7 @@ public class IconBrowserWidget : IDataWindowWidget // continue; if (!texm.TryGetIconPath(new((uint)iconId), out var path)) continue; + result.Add((iconId, path)); } @@ -82,17 +84,17 @@ public class IconBrowserWidget : IDataWindowWidget { this.RecalculateIndexRange(); - if (ImGui.BeginChild("ScrollableSection"u8, ImGui.GetContentRegionAvail(), false, ImGuiWindowFlags.NoMove)) + using (var child = ImRaii.Child("ScrollableSection"u8, ImGui.GetContentRegionAvail(), false, ImGuiWindowFlags.NoMove)) { - var itemsPerRow = (int)MathF.Floor( - ImGui.GetContentRegionMax().X / (this.iconSize.X + ImGui.GetStyle().ItemSpacing.X)); - var itemHeight = this.iconSize.Y + ImGui.GetStyle().ItemSpacing.Y; + if (child.Success) + { + var itemsPerRow = (int)MathF.Floor(ImGui.GetContentRegionMax().X / (this.iconSize.X + ImGui.GetStyle().ItemSpacing.X)); + var itemHeight = this.iconSize.Y + ImGui.GetStyle().ItemSpacing.Y; - ImGuiClip.ClippedDraw(this.valueRange!, this.DrawIcon, itemsPerRow, itemHeight); + ImGuiClip.ClippedDraw(this.valueRange!, this.DrawIcon, itemsPerRow, itemHeight); + } } - ImGui.EndChild(); - this.ProcessMouseDragging(); } } @@ -118,16 +120,16 @@ public class IconBrowserWidget : IDataWindowWidget { ImGui.Columns(2); - ImGui.PushItemWidth(ImGui.GetContentRegionAvail().X); - if (ImGui.InputInt("##StartRange"u8, ref this.startRange, 0, 0)) + ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); + if (ImGui.InputInt("##StartRange"u8, ref this.startRange)) { this.startRange = Math.Clamp(this.startRange, 0, MaxIconId); this.valueRange = null; } ImGui.NextColumn(); - ImGui.PushItemWidth(ImGui.GetContentRegionAvail().X); - if (ImGui.InputInt("##StopRange"u8, ref this.stopRange, 0, 0)) + ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); + if (ImGui.InputInt("##StopRange"u8, ref this.stopRange)) { this.stopRange = Math.Clamp(this.stopRange, 0, MaxIconId); this.valueRange = null; @@ -151,6 +153,10 @@ public class IconBrowserWidget : IDataWindowWidget var texm = Service.Get(); var cursor = ImGui.GetCursorScreenPos(); + var white = ImGui.GetColorU32(ImGuiColors.DalamudWhite); + var red = ImGui.GetColorU32(ImGuiColors.DalamudRed); + var drawList = ImGui.GetWindowDrawList(); + if (texm.Shared.GetFromGameIcon(iconId).TryGetWrap(out var texture, out var exc)) { ImGui.Image(texture.Handle, this.iconSize); @@ -158,21 +164,17 @@ public class IconBrowserWidget : IDataWindowWidget // If we have the option to show a tooltip image, draw the image, but make sure it's not too big. if (ImGui.IsItemHovered() && this.showTooltipImage) { - ImGui.BeginTooltip(); + using var tooltip = ImRaii.Tooltip(); var scale = GetImageScaleFactor(texture); var textSize = ImGui.CalcTextSize(iconId.ToString()); - ImGui.SetCursorPosX( - texture.Size.X * scale / 2.0f - textSize.X / 2.0f + ImGui.GetStyle().FramePadding.X * 2.0f); + ImGui.SetCursorPosX((texture.Size.X * scale / 2.0f - (textSize.X / 2.0f)) + (ImGui.GetStyle().FramePadding.X * 2.0f)); ImGui.Text(iconId.ToString()); ImGui.Image(texture.Handle, texture.Size * scale); - ImGui.EndTooltip(); } - - // else, just draw the iconId. - else if (ImGui.IsItemHovered()) + else if (ImGui.IsItemHovered()) // else, just draw the iconId. { ImGui.SetTooltip(iconId.ToString()); } @@ -185,10 +187,7 @@ public class IconBrowserWidget : IDataWindowWidget Task.FromResult(texture.CreateWrapSharingLowLevelResource())); } - ImGui.GetWindowDrawList().AddRect( - cursor, - cursor + this.iconSize, - ImGui.GetColorU32(ImGuiColors.DalamudWhite)); + drawList.AddRect(cursor, cursor + this.iconSize, white); } else if (exc is not null) { @@ -197,19 +196,13 @@ public class IconBrowserWidget : IDataWindowWidget { var iconText = FontAwesomeIcon.Ban.ToIconString(); var textSize = ImGui.CalcTextSize(iconText); - ImGui.GetWindowDrawList().AddText( - cursor + ((this.iconSize - textSize) / 2), - ImGui.GetColorU32(ImGuiColors.DalamudRed), - iconText); + drawList.AddText(cursor + ((this.iconSize - textSize) / 2), red, iconText); } if (ImGui.IsItemHovered()) ImGui.SetTooltip($"{iconId}\n{exc}"); - ImGui.GetWindowDrawList().AddRect( - cursor, - cursor + this.iconSize, - ImGui.GetColorU32(ImGuiColors.DalamudRed)); + drawList.AddRect(cursor, cursor + this.iconSize, red); } else { @@ -218,18 +211,12 @@ public class IconBrowserWidget : IDataWindowWidget ImGui.Dummy(this.iconSize); var textSize = ImGui.CalcTextSize(text); - ImGui.GetWindowDrawList().AddText( - cursor + ((this.iconSize - textSize) / 2), - color, - text); + drawList.AddText(cursor + ((this.iconSize - textSize) / 2), color, text); if (ImGui.IsItemHovered()) ImGui.SetTooltip(iconId.ToString()); - ImGui.GetWindowDrawList().AddRect( - cursor, - cursor + this.iconSize, - color); + drawList.AddRect(cursor, cursor + this.iconSize, color); } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs index 4327fa12f..2581f902d 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ImGuiWidget.cs @@ -54,8 +54,7 @@ internal class ImGuiWidget : IDataWindowWidget ImGui.Separator(); - ImGui.Text( - $"WindowSystem.TimeSinceLastAnyFocus: {WindowSystem.TimeSinceLastAnyFocus.TotalMilliseconds:0}ms"); + ImGui.Text($"WindowSystem.TimeSinceLastAnyFocus: {WindowSystem.TimeSinceLastAnyFocus.TotalMilliseconds:0}ms"); ImGui.Separator(); @@ -79,45 +78,24 @@ internal class ImGuiWidget : IDataWindowWidget switch (this.notificationTemplate.IconInt) { case 1 or 2: - ImGui.InputText( - "Icon Text##iconText"u8, - ref this.notificationTemplate.IconText, - 255); + ImGui.InputText("Icon Text##iconText"u8, ref this.notificationTemplate.IconText, 255); break; case 5 or 6: - ImGui.Combo( - "Asset##iconAssetCombo", - ref this.notificationTemplate.IconAssetInt, - NotificationTemplate.AssetSources); + ImGui.Combo("Asset##iconAssetCombo", ref this.notificationTemplate.IconAssetInt, NotificationTemplate.AssetSources); break; case 3 or 7: - ImGui.InputText( - "Game Path##iconText"u8, - ref this.notificationTemplate.IconText, - 255); + ImGui.InputText("Game Path##iconText"u8, ref this.notificationTemplate.IconText, 255); break; case 4 or 8: - ImGui.InputText( - "File Path##iconText"u8, - ref this.notificationTemplate.IconText, - 255); + ImGui.InputText("File Path##iconText"u8, ref this.notificationTemplate.IconText, 255); break; } - ImGui.Combo( - "Initial Duration", - ref this.notificationTemplate.InitialDurationInt, - NotificationTemplate.InitialDurationTitles); + ImGui.Combo("Initial Duration", ref this.notificationTemplate.InitialDurationInt, NotificationTemplate.InitialDurationTitles); - ImGui.Combo( - "Extension Duration", - ref this.notificationTemplate.HoverExtendDurationInt, - NotificationTemplate.HoverExtendDurationTitles); + ImGui.Combo("Extension Duration", ref this.notificationTemplate.HoverExtendDurationInt, NotificationTemplate.HoverExtendDurationTitles); - ImGui.Combo( - "Progress", - ref this.notificationTemplate.ProgressMode, - NotificationTemplate.ProgressModeTitles); + ImGui.Combo("Progress", ref this.notificationTemplate.ProgressMode, NotificationTemplate.ProgressModeTitles); ImGui.Checkbox("Respect UI Hidden"u8, ref this.notificationTemplate.RespectUiHidden); @@ -127,14 +105,11 @@ internal class ImGuiWidget : IDataWindowWidget ImGui.Checkbox("User Dismissable"u8, ref this.notificationTemplate.UserDismissable); - ImGui.Checkbox( - "Action Bar (always on if not user dismissable for the example)"u8, - ref this.notificationTemplate.ActionBar); + ImGui.Checkbox("Action Bar (always on if not user dismissable for the example)"u8, ref this.notificationTemplate.ActionBar); if (ImGui.Button("Add notification"u8)) { - var text = - "Bla bla bla bla bla bla bla bla bla bla bla.\nBla bla bla bla bla bla bla bla bla bla bla bla bla bla."; + var text = "Bla bla bla bla bla bla bla bla bla bla bla.\nBla bla bla bla bla bla bla bla bla bla bla bla bla bla."; NewRandom(out var title, out var type, out var progress); if (this.notificationTemplate.ManualTitle) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs index f5b26c04c..818e3fabc 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs @@ -22,6 +22,11 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class InventoryWidget : IDataWindowWidget { + private const ImGuiTableFlags TableFlags = ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | + ImGuiTableFlags.ScrollY | ImGuiTableFlags.NoSavedSettings; + + private const ImGuiTableFlags InnerTableFlags = ImGuiTableFlags.BordersInner | ImGuiTableFlags.NoSavedSettings; + private DataManager dataManager; private TextureManager textureManager; private GameInventoryType? selectedInventoryType = GameInventoryType.Inventory1; @@ -64,7 +69,7 @@ internal class InventoryWidget : IDataWindowWidget private unsafe void DrawInventoryTypeList() { - using var table = ImRaii.Table("InventoryTypeTable"u8, 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY | ImGuiTableFlags.NoSavedSettings, new Vector2(300, -1)); + using var table = ImRaii.Table("InventoryTypeTable"u8, 2, TableFlags, new Vector2(300, -1)); if (!table) return; ImGui.TableSetupColumn("Type"u8); @@ -107,7 +112,7 @@ internal class InventoryWidget : IDataWindowWidget } } - private unsafe void DrawInventoryType(GameInventoryType inventoryType) + private void DrawInventoryType(GameInventoryType inventoryType) { var items = GameInventoryItem.GetReadOnlySpanOfInventory(inventoryType); if (items.IsEmpty) @@ -116,8 +121,9 @@ internal class InventoryWidget : IDataWindowWidget return; } - using var itemTable = ImRaii.Table("InventoryItemTable"u8, 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY | ImGuiTableFlags.NoSavedSettings); + using var itemTable = ImRaii.Table("InventoryItemTable"u8, 4, TableFlags); if (!itemTable) return; + ImGui.TableSetupColumn("Slot"u8, ImGuiTableColumnFlags.WidthFixed, 40); ImGui.TableSetupColumn("ItemId"u8, ImGuiTableColumnFlags.WidthFixed, 70); ImGui.TableSetupColumn("Quantity"u8, ImGuiTableColumnFlags.WidthFixed, 70); @@ -129,7 +135,7 @@ internal class InventoryWidget : IDataWindowWidget { var item = items[slotIndex]; - using var disableditem = ImRaii.Disabled(item.ItemId == 0); + using var disabledItem = ImRaii.Disabled(item.ItemId == 0); ImGui.TableNextRow(); ImGui.TableNextColumn(); // Slot @@ -154,11 +160,11 @@ internal class InventoryWidget : IDataWindowWidget if (ImGui.IsItemHovered()) { ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); - ImGui.BeginTooltip(); + + using var tooltip = ImRaii.Tooltip(); ImGui.Text("Click to copy IconId"u8); ImGui.Text($"ID: {iconId} – Size: {texture.Width}x{texture.Height}"); ImGui.Image(texture.Handle, new(texture.Width, texture.Height)); - ImGui.EndTooltip(); } if (ImGui.IsItemClicked()) @@ -169,7 +175,7 @@ internal class InventoryWidget : IDataWindowWidget using var itemNameColor = ImRaii.PushColor(ImGuiCol.Text, this.GetItemRarityColor(item.ItemId)); using var node = ImRaii.TreeNode($"{itemName}###{inventoryType}_{slotIndex}", ImGuiTreeNodeFlags.SpanAvailWidth); - itemNameColor.Dispose(); + itemNameColor.Pop(); using (var contextMenu = ImRaii.ContextPopupItem($"{inventoryType}_{slotIndex}_ContextMenu")) { @@ -184,7 +190,7 @@ internal class InventoryWidget : IDataWindowWidget if (!node) continue; - using var itemInfoTable = ImRaii.Table($"{inventoryType}_{slotIndex}_Table", 2, ImGuiTableFlags.BordersInner | ImGuiTableFlags.NoSavedSettings); + using var itemInfoTable = ImRaii.Table($"{inventoryType}_{slotIndex}_Table", 2, InnerTableFlags); if (!itemInfoTable) continue; ImGui.TableSetupColumn("Name"u8, ImGuiTableColumnFlags.WidthFixed, 150); @@ -266,7 +272,7 @@ internal class InventoryWidget : IDataWindowWidget ImGui.Text("Stains"u8); ImGui.TableNextColumn(); - using var stainTable = ImRaii.Table($"{inventoryType}_{slotIndex}_StainTable", 2, ImGuiTableFlags.BordersInner | ImGuiTableFlags.NoSavedSettings); + using var stainTable = ImRaii.Table($"{inventoryType}_{slotIndex}_StainTable", 2, InnerTableFlags); if (!stainTable) continue; ImGui.TableSetupColumn("Stain Id"u8, ImGuiTableColumnFlags.WidthFixed, 80); @@ -287,7 +293,7 @@ internal class InventoryWidget : IDataWindowWidget ImGui.Text("Materia"u8); ImGui.TableNextColumn(); - using var materiaTable = ImRaii.Table($"{inventoryType}_{slotIndex}_MateriaTable", 2, ImGuiTableFlags.BordersInner | ImGuiTableFlags.NoSavedSettings); + using var materiaTable = ImRaii.Table($"{inventoryType}_{slotIndex}_MateriaTable", 2, InnerTableFlags); if (!materiaTable) continue; ImGui.TableSetupColumn("Materia Id"u8, ImGuiTableColumnFlags.WidthFixed, 80); @@ -313,10 +319,12 @@ internal class InventoryWidget : IDataWindowWidget private uint GetItemRarityColor(uint itemId, bool isEdgeColor = false) { - if (ItemUtil.IsEventItem(itemId)) + var normalized = ItemUtil.GetBaseId(itemId); + + if (normalized.Kind == ItemKind.EventItem) return isEdgeColor ? 0xFF000000 : 0xFFFFFFFF; - if (!this.dataManager.Excel.GetSheet().TryGetRow(ItemUtil.GetBaseId(itemId).ItemId, out var item)) + if (!this.dataManager.Excel.GetSheet().TryGetRow(normalized.ItemId, out var item)) return isEdgeColor ? 0xFF000000 : 0xFFFFFFFF; var rowId = ItemUtil.GetItemRarityColorType(item.RowId, isEdgeColor); @@ -327,18 +335,12 @@ internal class InventoryWidget : IDataWindowWidget private uint GetItemIconId(uint itemId) { + var normalized = ItemUtil.GetBaseId(itemId); + // EventItem - if (ItemUtil.IsEventItem(itemId)) + if (normalized.Kind == ItemKind.EventItem) return this.dataManager.Excel.GetSheet().TryGetRow(itemId, out var eventItem) ? eventItem.Icon : 0u; - // HighQuality - if (ItemUtil.IsHighQuality(itemId)) - itemId -= 1_000_000; - - // Collectible - if (ItemUtil.IsCollectible(itemId)) - itemId -= 500_000; - - return this.dataManager.Excel.GetSheet().TryGetRow(itemId, out var item) ? item.Icon : 0u; + return this.dataManager.Excel.GetSheet().TryGetRow(normalized.ItemId, out var item) ? item.Icon : 0u; } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/KeyStateWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/KeyStateWidget.cs index 1b45b58fe..d3b021f7a 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/KeyStateWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/KeyStateWidget.cs @@ -1,6 +1,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Game.ClientState.Keys; using Dalamud.Interface.Colors; +using Dalamud.Interface.Utility.Raii; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; @@ -29,6 +30,7 @@ internal class KeyStateWidget : IDataWindowWidget { var keyState = Service.Get(); + // TODO: Use table instead of columns ImGui.Columns(4); var i = 0; @@ -37,11 +39,10 @@ internal class KeyStateWidget : IDataWindowWidget var code = (int)vkCode; var value = keyState[code]; - ImGui.PushStyleColor(ImGuiCol.Text, value ? ImGuiColors.HealerGreen : ImGuiColors.DPSRed); - - ImGui.Text($"{vkCode} ({code})"); - - ImGui.PopStyleColor(); + using (ImRaii.PushColor(ImGuiCol.Text, value ? ImGuiColors.HealerGreen : ImGuiColors.DPSRed)) + { + ImGui.Text($"{vkCode} ({code})"); + } i++; if (i % 24 == 0) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/MarketBoardWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/MarketBoardWidget.cs index 382c42f91..a74c5f3d3 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/MarketBoardWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/MarketBoardWidget.cs @@ -15,6 +15,8 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class MarketBoardWidget : IDataWindowWidget { + private const ImGuiTableFlags TableFlags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg; + private readonly ConcurrentQueue<(IMarketBoardHistory MarketBoardHistory, IMarketBoardHistoryListing Listing)> marketBoardHistoryQueue = new(); private readonly ConcurrentQueue<(IMarketBoardCurrentOfferings MarketBoardCurrentOfferings, IMarketBoardItemListing Listing)> marketBoardCurrentOfferingsQueue = new(); private readonly ConcurrentQueue marketBoardPurchasesQueue = new(); @@ -99,49 +101,47 @@ internal class MarketBoardWidget : IDataWindowWidget this.marketBoardHistoryQueue.Clear(); } - using (var tabBar = ImRaii.TabBar("marketTabs"u8)) + using var tabBar = ImRaii.TabBar("marketTabs"u8); + if (!tabBar.Success) + return; + + using (var tabItem = ImRaii.TabItem("History"u8)) { - if (tabBar) + if (tabItem) { - using (var tabItem = ImRaii.TabItem("History"u8)) - { - if (tabItem) - { - ImGuiTable.DrawTable(string.Empty, this.marketBoardHistoryQueue, this.DrawMarketBoardHistory, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg, "Item ID", "Quantity", "Is HQ?", "Sale Price", "Buyer Name", "Purchase Time"); - } - } + ImGuiTable.DrawTable("history-table", this.marketBoardHistoryQueue, this.DrawMarketBoardHistory, TableFlags, "Item ID", "Quantity", "Is HQ?", "Sale Price", "Buyer Name", "Purchase Time"); + } + } - using (var tabItem = ImRaii.TabItem("Offerings"u8)) - { - if (tabItem) - { - ImGuiTable.DrawTable(string.Empty, this.marketBoardCurrentOfferingsQueue, this.DrawMarketBoardCurrentOfferings, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg, "Item ID", "Quantity", "Is HQ?", "Price Per Unit", "Retainer Name"); - } - } + using (var tabItem = ImRaii.TabItem("Offerings"u8)) + { + if (tabItem) + { + ImGuiTable.DrawTable("offerings-table", this.marketBoardCurrentOfferingsQueue, this.DrawMarketBoardCurrentOfferings, TableFlags, "Item ID", "Quantity", "Is HQ?", "Price Per Unit", "Retainer Name"); + } + } - using (var tabItem = ImRaii.TabItem("Purchases"u8)) - { - if (tabItem) - { - ImGuiTable.DrawTable(string.Empty, this.marketBoardPurchasesQueue, this.DrawMarketBoardPurchases, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg, "Item ID", "Quantity"); - } - } + using (var tabItem = ImRaii.TabItem("Purchases"u8)) + { + if (tabItem) + { + ImGuiTable.DrawTable("purchases-table", this.marketBoardPurchasesQueue, this.DrawMarketBoardPurchases, TableFlags, "Item ID", "Quantity"); + } + } - using (var tabItem = ImRaii.TabItem("Purchase Requests"u8)) - { - if (tabItem) - { - ImGuiTable.DrawTable(string.Empty, this.marketBoardPurchaseRequestsQueue, this.DrawMarketBoardPurchaseRequests, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg, "Item ID", "Is HQ?", "Quantity", "Price Per Unit", "Total Tax", "City ID", "Listing ID", "Retainer ID"); - } - } + using (var tabItem = ImRaii.TabItem("Purchase Requests"u8)) + { + if (tabItem) + { + ImGuiTable.DrawTable("requests-table", this.marketBoardPurchaseRequestsQueue, this.DrawMarketBoardPurchaseRequests, TableFlags, "Item ID", "Is HQ?", "Quantity", "Price Per Unit", "Total Tax", "City ID", "Listing ID", "Retainer ID"); + } + } - using (var tabItem = ImRaii.TabItem("Taxes"u8)) - { - if (tabItem) - { - ImGuiTable.DrawTable(string.Empty, this.marketTaxRatesQueue, this.DrawMarketTaxRates, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg, "Uldah", "Limsa Lominsa", "Gridania", "Ishgard", "Kugane", "Crystarium", "Sharlayan", "Tuliyollal", "Valid Until"); - } - } + using (var tabItem = ImRaii.TabItem("Taxes"u8)) + { + if (tabItem) + { + ImGuiTable.DrawTable("taxes-table", this.marketTaxRatesQueue, this.DrawMarketTaxRates, TableFlags, "Uldah", "Limsa Lominsa", "Gridania", "Ishgard", "Kugane", "Crystarium", "Sharlayan", "Tuliyollal", "Valid Until"); } } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs index 7761a18b4..ae173578a 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs @@ -209,7 +209,7 @@ internal class NetworkMonitorWidget : IDataWindowWidget private readonly record struct NetworkPacketData(ushort OpCode, NetworkMessageDirection Direction, uint SourceActorId, uint TargetActorId) #pragma warning restore SA1313 { - public readonly IReadOnlyList Data = Array.Empty(); + public readonly IReadOnlyList Data = []; public NetworkPacketData(NetworkMonitorWidget widget, ushort opCode, NetworkMessageDirection direction, uint sourceActorId, uint targetActorId, nint dataPtr) : this(opCode, direction, sourceActorId, targetActorId) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/NounProcessorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/NounProcessorWidget.cs index eac8b5a52..968254ceb 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/NounProcessorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/NounProcessorWidget.cs @@ -55,8 +55,8 @@ internal class NounProcessorWidget : IDataWindowWidget private ClientLanguage[] languages = []; private string[] languageNames = []; - private int selectedSheetNameIndex = 0; - private int selectedLanguageIndex = 0; + private int selectedSheetNameIndex; + private int selectedLanguageIndex; private int rowId = 1; private int amount = 1; @@ -84,7 +84,6 @@ internal class NounProcessorWidget : IDataWindowWidget { var nounProcessor = Service.Get(); var dataManager = Service.Get(); - var clientState = Service.Get(); var sheetType = NounSheets.ElementAt(this.selectedSheetNameIndex); var language = this.languages[this.selectedLanguageIndex]; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs index dd5dc7472..6a6c0f8be 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ObjectTableWidget.cs @@ -14,6 +14,11 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// internal class ObjectTableWidget : IDataWindowWidget { + private const ImGuiWindowFlags CharacterWindowFlags = ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.AlwaysAutoResize | + ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoMove | + ImGuiWindowFlags.NoMouseInputs | ImGuiWindowFlags.NoDocking | + ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoNav; + private bool resolveGameData; private bool drawCharacters; private float maxCharaDrawDistance = 20.0f; @@ -49,74 +54,66 @@ internal class ObjectTableWidget : IDataWindowWidget if (objectTable.LocalPlayer == null) { ImGui.Text("LocalPlayer null."u8); + return; } - else if (clientState.IsPvPExcludingDen) + + if (clientState.IsPvPExcludingDen) { ImGui.Text("Cannot access object table while in PvP."u8); + return; } - else + + stateString += $"ObjectTableLen: {objectTable.Length}\n"; + stateString += $"LocalPlayerName: {playerState.CharacterName}\n"; + stateString += $"CurrentWorldName: {(this.resolveGameData ? playerState.CurrentWorld.ValueNullable?.Name : playerState.CurrentWorld.RowId.ToString())}\n"; + stateString += $"HomeWorldName: {(this.resolveGameData ? playerState.HomeWorld.ValueNullable?.Name : playerState.HomeWorld.RowId.ToString())}\n"; + stateString += $"LocalCID: {playerState.ContentId:X}\n"; + stateString += $"LastLinkedItem: {chatGui.LastLinkedItemId}\n"; + stateString += $"TerritoryType: {clientState.TerritoryType}\n\n"; + + ImGui.Text(stateString); + + ImGui.Checkbox("Draw characters on screen"u8, ref this.drawCharacters); + ImGui.SliderFloat("Draw Distance"u8, ref this.maxCharaDrawDistance, 2f, 40f); + + for (var i = 0; i < objectTable.Length; i++) { - stateString += $"ObjectTableLen: {objectTable.Length}\n"; - stateString += $"LocalPlayerName: {playerState.CharacterName}\n"; - stateString += $"CurrentWorldName: {(this.resolveGameData ? playerState.CurrentWorld.ValueNullable?.Name : playerState.CurrentWorld.RowId.ToString())}\n"; - stateString += $"HomeWorldName: {(this.resolveGameData ? playerState.HomeWorld.ValueNullable?.Name : playerState.HomeWorld.RowId.ToString())}\n"; - stateString += $"LocalCID: {playerState.ContentId:X}\n"; - stateString += $"LastLinkedItem: {chatGui.LastLinkedItemId}\n"; - stateString += $"TerritoryType: {clientState.TerritoryType}\n\n"; + var obj = objectTable[i]; - ImGui.Text(stateString); + if (obj == null) + continue; - ImGui.Checkbox("Draw characters on screen"u8, ref this.drawCharacters); - ImGui.SliderFloat("Draw Distance"u8, ref this.maxCharaDrawDistance, 2f, 40f); + Util.PrintGameObject(obj, i.ToString(), this.resolveGameData); - for (var i = 0; i < objectTable.Length; i++) + if (this.drawCharacters && gameGui.WorldToScreen(obj.Position, out var screenCoords)) { - var obj = objectTable[i]; + // So, while WorldToScreen will return false if the point is off of game client screen, to + // to avoid performance issues, we have to manually determine if creating a window would + // produce a new viewport, and skip rendering it if so + var objectText = $"{obj.Address:X}:{obj.GameObjectId:X}[{i}] - {obj.ObjectKind} - {obj.Name}"; - if (obj == null) + var screenPos = ImGui.GetMainViewport().Pos; + var screenSize = ImGui.GetMainViewport().Size; + + var windowSize = ImGui.CalcTextSize(objectText); + + // Add some extra safety padding + windowSize.X += ImGui.GetStyle().WindowPadding.X + 10; + windowSize.Y += ImGui.GetStyle().WindowPadding.Y + 10; + + if (screenCoords.X + windowSize.X > screenPos.X + screenSize.X || + screenCoords.Y + windowSize.Y > screenPos.Y + screenSize.Y) continue; - Util.PrintGameObject(obj, i.ToString(), this.resolveGameData); + if (obj.YalmDistanceX > this.maxCharaDrawDistance) + continue; - if (this.drawCharacters && gameGui.WorldToScreen(obj.Position, out var screenCoords)) - { - // So, while WorldToScreen will return false if the point is off of game client screen, to - // to avoid performance issues, we have to manually determine if creating a window would - // produce a new viewport, and skip rendering it if so - var objectText = $"{obj.Address.ToInt64():X}:{obj.GameObjectId:X}[{i}] - {obj.ObjectKind} - {obj.Name}"; + ImGui.SetNextWindowPos(new Vector2(screenCoords.X, screenCoords.Y)); + ImGui.SetNextWindowBgAlpha(Math.Max(1f - (obj.YalmDistanceX / this.maxCharaDrawDistance), 0.2f)); - var screenPos = ImGui.GetMainViewport().Pos; - var screenSize = ImGui.GetMainViewport().Size; - - var windowSize = ImGui.CalcTextSize(objectText); - - // Add some extra safety padding - windowSize.X += ImGui.GetStyle().WindowPadding.X + 10; - windowSize.Y += ImGui.GetStyle().WindowPadding.Y + 10; - - if (screenCoords.X + windowSize.X > screenPos.X + screenSize.X || - screenCoords.Y + windowSize.Y > screenPos.Y + screenSize.Y) - continue; - - if (obj.YalmDistanceX > this.maxCharaDrawDistance) - continue; - - ImGui.SetNextWindowPos(new Vector2(screenCoords.X, screenCoords.Y)); - - ImGui.SetNextWindowBgAlpha(Math.Max(1f - (obj.YalmDistanceX / this.maxCharaDrawDistance), 0.2f)); - if (ImGui.Begin( - $"Actor{i}##ActorWindow{i}", - ImGuiWindowFlags.NoDecoration | - ImGuiWindowFlags.AlwaysAutoResize | - ImGuiWindowFlags.NoSavedSettings | - ImGuiWindowFlags.NoMove | - ImGuiWindowFlags.NoMouseInputs | - ImGuiWindowFlags.NoDocking | - ImGuiWindowFlags.NoFocusOnAppearing | - ImGuiWindowFlags.NoNav)) - ImGui.Text(objectText); - ImGui.End(); - } + if (ImGui.Begin($"Actor{i}##ActorWindow{i}", CharacterWindowFlags)) + ImGui.Text(objectText); + ImGui.End(); } } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/PartyListWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/PartyListWidget.cs index 4033e4f41..597078f21 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/PartyListWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/PartyListWidget.cs @@ -33,9 +33,9 @@ internal class PartyListWidget : IDataWindowWidget ImGui.Checkbox("Resolve GameData"u8, ref this.resolveGameData); - ImGui.Text($"GroupManager: {partyList.GroupManagerAddress.ToInt64():X}"); - ImGui.Text($"GroupList: {partyList.GroupListAddress.ToInt64():X}"); - ImGui.Text($"AllianceList: {partyList.AllianceListAddress.ToInt64():X}"); + ImGui.Text($"GroupManager: {partyList.GroupManagerAddress:X}"); + ImGui.Text($"GroupList: {partyList.GroupListAddress:X}"); + ImGui.Text($"AllianceList: {partyList.AllianceListAddress:X}"); ImGui.Text($"{partyList.Length} Members"); @@ -48,7 +48,7 @@ internal class PartyListWidget : IDataWindowWidget continue; } - ImGui.Text($"[{i}] {member.Address.ToInt64():X} - {member.Name} - {member.GameObject?.GameObjectId}"); + ImGui.Text($"[{i}] {member.Address:X} - {member.Name} - {member.GameObject?.GameObjectId ?? 0}"); if (this.resolveGameData) { var actor = member.GameObject; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringCreatorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringCreatorWidget.cs index d43d3b7b2..a11bc3719 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringCreatorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringCreatorWidget.cs @@ -38,6 +38,11 @@ internal class SeStringCreatorWidget : IDataWindowWidget { private const LinkMacroPayloadType DalamudLinkType = (LinkMacroPayloadType)Payload.EmbeddedInfoType.DalamudLink - 1; + private const ImGuiTableFlags TableFlags = ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg | + ImGuiTableFlags.ScrollY | ImGuiTableFlags.NoSavedSettings; + + private static readonly string[] TextEntryTypeOptions = ["String", "Macro", "Fixed"]; + private readonly Dictionary expressionNames = new() { { MacroCode.SetResetTime, ["Hour", "WeekDay"] }, @@ -191,7 +196,7 @@ internal class SeStringCreatorWidget : IDataWindowWidget if (contentWidth != this.lastContentWidth) { var originalWidth = this.lastContentWidth != 0 ? this.lastContentWidth : contentWidth; - this.inputsWidth = this.inputsWidth / originalWidth * contentWidth; + this.inputsWidth = (this.inputsWidth / originalWidth) * contentWidth; this.lastContentWidth = contentWidth; } @@ -258,7 +263,7 @@ internal class SeStringCreatorWidget : IDataWindowWidget using var tab = ImRaii.TabItem("Global Parameters"u8); if (!tab) return; - using var table = ImRaii.Table("GlobalParametersTable"u8, 5, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.NoSavedSettings); + using var table = ImRaii.Table("GlobalParametersTable"u8, 5, TableFlags); if (!table) return; ImGui.TableSetupColumn("Id"u8, ImGuiTableColumnFlags.WidthFixed, 40); @@ -541,18 +546,16 @@ internal class SeStringCreatorWidget : IDataWindowWidget ImGui.SameLine(); ImGui.SetNextItemWidth(90 * ImGuiHelpers.GlobalScale); - using (var dropdown = ImRaii.Combo("##Language"u8, this.language.ToString() ?? "Language...")) + using var dropdown = ImRaii.Combo("##Language"u8, this.language.ToString() ?? "Language..."); + if (dropdown) { - if (dropdown) + var values = Enum.GetValues().OrderBy(lang => lang.ToString()); + foreach (var value in values) { - var values = Enum.GetValues().OrderBy((ClientLanguage lang) => lang.ToString()); - foreach (var value in values) + if (ImGui.Selectable(Enum.GetName(value), value == this.language)) { - if (ImGui.Selectable(Enum.GetName(value), value == this.language)) - { - this.language = value; - this.UpdateInputString(); - } + this.language = value; + this.UpdateInputString(); } } } @@ -572,7 +575,7 @@ internal class SeStringCreatorWidget : IDataWindowWidget try { var headerFile = dataManager.GameData.GetFile($"exd/{sheetName}.exh"); - if (headerFile.Header.Variant != ExcelVariant.Default) + if (headerFile == null || headerFile.Header.Variant != ExcelVariant.Default) return false; var sheet = dataManager.Excel.GetSheet(Language.English, sheetName); @@ -668,11 +671,10 @@ internal class SeStringCreatorWidget : IDataWindowWidget catch (Exception e) { ImGui.Text(e.Message); - return; } } - private unsafe void DrawInputs() + private void DrawInputs() { using var child = ImRaii.Child("Inputs"u8, new Vector2(this.inputsWidth, -1)); if (!child) return; @@ -688,8 +690,6 @@ internal class SeStringCreatorWidget : IDataWindowWidget var arrowUpButtonSize = this.GetIconButtonSize(FontAwesomeIcon.ArrowUp); var arrowDownButtonSize = this.GetIconButtonSize(FontAwesomeIcon.ArrowDown); - var trashButtonSize = this.GetIconButtonSize(FontAwesomeIcon.Trash); - var terminalButtonSize = this.GetIconButtonSize(FontAwesomeIcon.Terminal); var entryToRemove = -1; var entryToMoveUp = -1; @@ -706,7 +706,7 @@ internal class SeStringCreatorWidget : IDataWindowWidget ImGui.TableNextColumn(); // Type var type = (int)entry.Type; ImGui.SetNextItemWidth(-1); - if (ImGui.Combo($"##Type{i}", ref type, ["String", "Macro", "Fixed"])) + if (ImGui.Combo($"##Type{i}", ref type, TextEntryTypeOptions)) { entry.Type = (TextEntryType)type; updateString |= true; @@ -798,7 +798,7 @@ internal class SeStringCreatorWidget : IDataWindowWidget } } - private unsafe void UpdateInputString(bool resetLocalParameters = true) + private void UpdateInputString(bool resetLocalParameters = true) { using var rssb = new RentedSeStringBuilder(); @@ -1022,14 +1022,14 @@ internal class SeStringCreatorWidget : IDataWindowWidget if (macroCode is MacroCode.JaNoun or MacroCode.EnNoun or MacroCode.DeNoun or MacroCode.FrNoun && exprIdx == 1) { - var language = macroCode switch + var macroLanguage = macroCode switch { MacroCode.JaNoun => ClientLanguage.Japanese, MacroCode.DeNoun => ClientLanguage.German, MacroCode.FrNoun => ClientLanguage.French, _ => ClientLanguage.English, }; - var articleTypeEnumType = language switch + var articleTypeEnumType = macroLanguage switch { ClientLanguage.Japanese => typeof(JapaneseArticleType), ClientLanguage.German => typeof(GermanArticleType), @@ -1208,12 +1208,10 @@ internal class SeStringCreatorWidget : IDataWindowWidget if (expressionType == (int)ExpressionType.LocalNumber) { parameters[index] = new SeStringParameter(0); - return; } else if (expressionType == (int)ExpressionType.LocalString) { parameters[index] = new SeStringParameter(string.Empty); - return; } } } diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/ServicesWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/ServicesWidget.cs index 3ddc2a888..a4351248b 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/ServicesWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/ServicesWidget.cs @@ -66,11 +66,10 @@ internal class ServicesWidget : IDataWindowWidget var margin = ImGui.CalcTextSize("W\nW\nW"u8); var rowHeight = cellPad.Y * 3; var width = ImGui.GetContentRegionAvail().X; - if (ImGui.BeginChild( - "dependency-graph"u8, - new(width, (this.dependencyNodes.Count * (rowHeight + margin.Y)) + cellPad.Y), - false, - ImGuiWindowFlags.HorizontalScrollbar)) + var childSize = new Vector2(width, (this.dependencyNodes.Count * (rowHeight + margin.Y)) + cellPad.Y); + + using var child = ImRaii.Child("dependency-graph"u8, childSize, false, ImGuiWindowFlags.HorizontalScrollbar); + if (child.Success) { const uint rectBaseBorderColor = 0xFFFFFFFF; const uint rectHoverFillColor = 0xFF404040; @@ -118,10 +117,8 @@ internal class ServicesWidget : IDataWindowWidget hoveredNode = node; if (ImGui.IsMouseClicked(ImGuiMouseButton.Left)) { - if (this.selectedNodes.Contains(node.Type)) + if (!this.selectedNodes.Add(node.Type)) this.selectedNodes.Remove(node.Type); - else - this.selectedNodes.Add(node.Type); } } @@ -195,13 +192,11 @@ internal class ServicesWidget : IDataWindowWidget ImGui.SetTooltip(node.BlockingReason); ImGui.SetCursorPos((new Vector2(rc.X, rc.Y) - pos) + ((cellSize - textSize) / 2)); - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); + using var pushedStyle = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero); ImGui.Text(node.DisplayedName); ImGui.SameLine(); - ImGui.PushStyleColor(ImGuiCol.Text, node.TypeSuffixColor); + using var pushedColor = ImRaii.PushColor(ImGuiCol.Text, node.TypeSuffixColor); ImGui.Text(node.TypeSuffix); - ImGui.PopStyleVar(); - ImGui.PopStyleColor(); } } @@ -233,7 +228,6 @@ internal class ServicesWidget : IDataWindowWidget ImGui.SetCursorPos(default); ImGui.Dummy(new(maxRowWidth, this.dependencyNodes.Count * rowHeight)); - ImGui.EndChild(); } } From afa7b0c1f3d4330c1ec87bee17876978d46f30ab Mon Sep 17 00:00:00 2001 From: wolfcomp <4028289+wolfcomp@users.noreply.github.com> Date: Tue, 27 Jan 2026 17:30:58 +0100 Subject: [PATCH 62/99] Improve parameter verification logic in HookVerifier (#2596) * Improve parameter verification logic in HookVerifier Refactor HookVerifier to enhance parameter type checking and add utility methods for size calculations. * Reverse bool check * Fix type size check on return type * Fix non static member in static class * Fix compiler errors * Fix SizeOf calls * Fix IsStruct call * Cleanup some warnings --- .../Internal/Verification/HookVerifier.cs | 54 +++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/Dalamud/Hooking/Internal/Verification/HookVerifier.cs b/Dalamud/Hooking/Internal/Verification/HookVerifier.cs index ad68ae38e..ebe6851ce 100644 --- a/Dalamud/Hooking/Internal/Verification/HookVerifier.cs +++ b/Dalamud/Hooking/Internal/Verification/HookVerifier.cs @@ -1,8 +1,13 @@ using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Dalamud.Game; using Dalamud.Logging.Internal; +using InteropGenerator.Runtime; + namespace Dalamud.Hooking.Internal.Verification; /// @@ -19,11 +24,13 @@ internal static class HookVerifier new( "ActorControlSelf", "E8 ?? ?? ?? ?? 0F B7 0B 83 E9 64", - typeof(ActorControlSelfDelegate), + typeof(ActorControlSelfDelegate), // TODO: change this to CS delegate "Signature changed in Patch 7.4") // 7.4 (new parameters) ]; - private delegate void ActorControlSelfDelegate(uint category, uint eventId, uint param1, uint param2, uint param3, uint param4, uint param5, uint param6, uint param7, uint param8, ulong targetId, byte param9); + private static readonly string ClientStructsInteropNamespacePrefix = string.Join(".", nameof(FFXIVClientStructs), nameof(FFXIVClientStructs.Interop)); + + private delegate void ActorControlSelfDelegate(uint category, uint eventId, uint param1, uint param2, uint param3, uint param4, uint param5, uint param6, uint param7, uint param8, ulong targetId, byte param9); // TODO: change this to CS delegate /// /// Initializes a new instance of the class. @@ -71,7 +78,7 @@ internal static class HookVerifier var enforcedInvoke = entry.TargetDelegateType.GetMethod("Invoke")!; // Compare Return Type - var mismatch = passedInvoke.ReturnType != enforcedInvoke.ReturnType; + var mismatch = !CheckParam(passedInvoke.ReturnType, enforcedInvoke.ReturnType); // Compare Parameter Count var passedParams = passedInvoke.GetParameters(); @@ -86,7 +93,7 @@ internal static class HookVerifier // Compare Parameter Types for (var i = 0; i < passedParams.Length; i++) { - if (passedParams[i].ParameterType != enforcedParams[i].ParameterType) + if (!CheckParam(passedParams[i].ParameterType, enforcedParams[i].ParameterType)) { mismatch = true; break; @@ -100,6 +107,45 @@ internal static class HookVerifier } } + private static bool CheckParam(Type paramLeft, Type paramRight) + { + var sameType = paramLeft == paramRight; + return sameType || SizeOf(paramLeft) == SizeOf(paramRight); + } + + private static int SizeOf(Type type) + { + return type switch { + _ when type == typeof(sbyte) || type == typeof(byte) || type == typeof(bool) => 1, + _ when type == typeof(char) || type == typeof(short) || type == typeof(ushort) || type == typeof(Half) => 2, + _ when type == typeof(int) || type == typeof(uint) || type == typeof(float) => 4, + _ when type == typeof(long) || type == typeof(ulong) || type == typeof(double) || type.IsPointer || type.IsFunctionPointer || type.IsUnmanagedFunctionPointer || (type.Name == "Pointer`1" && type.Namespace.AsSpan().SequenceEqual(ClientStructsInteropNamespacePrefix)) || type == typeof(CStringPointer) => 8, + _ when type.Name.StartsWith("FixedSizeArray") => SizeOf(type.GetGenericArguments()[0]) * int.Parse(type.Name[14..type.Name.IndexOf('`')]), + _ when type.GetCustomAttribute() is { Length: var length } => SizeOf(type.GetGenericArguments()[0]) * length, + _ when IsStruct(type) && !type.IsGenericType && (type.StructLayoutAttribute?.Value ?? LayoutKind.Sequential) != LayoutKind.Sequential => type.StructLayoutAttribute?.Size ?? (int?)typeof(Unsafe).GetMethod("SizeOf")?.MakeGenericMethod(type).Invoke(null, null) ?? 0, + _ when type.IsEnum => SizeOf(Enum.GetUnderlyingType(type)), + _ when type.IsGenericType => Marshal.SizeOf(Activator.CreateInstance(type)!), + _ => GetSizeOf(type), + }; + } + + private static int GetSizeOf(Type type) + { + try + { + return Marshal.SizeOf(Activator.CreateInstance(type)!); + } + catch + { + return 0; + } + } + + private static bool IsStruct(Type type) + { + return type != typeof(decimal) && type is { IsValueType: true, IsPrimitive: false, IsEnum: false }; + } + private record VerificationEntry(string Name, string Signature, Type TargetDelegateType, string Message) { public nint Address { get; set; } From 3abf7bb00bc834be650f784a322870510245fefa Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Tue, 27 Jan 2026 17:35:55 +0100 Subject: [PATCH 63/99] Rework NetworkMonitorWidget, remove GameNetwork (#2593) * Rework NetworkMonitorWidget, remove GameNetwork * Rework packet filtering --- Dalamud/Game/Network/GameNetwork.cs | 147 -------- .../Network/GameNetworkAddressResolver.cs | 20 - .../Game/Network/Internal/NetworkHandlers.cs | 5 +- .../Game/Network/NetworkMessageDirection.cs | 17 - .../Data/Widgets/NetworkMonitorWidget.cs | 341 +++++++++++------- Dalamud/Plugin/Services/IGameNetwork.cs | 27 -- 6 files changed, 212 insertions(+), 345 deletions(-) delete mode 100644 Dalamud/Game/Network/GameNetwork.cs delete mode 100644 Dalamud/Game/Network/GameNetworkAddressResolver.cs delete mode 100644 Dalamud/Game/Network/NetworkMessageDirection.cs delete mode 100644 Dalamud/Plugin/Services/IGameNetwork.cs diff --git a/Dalamud/Game/Network/GameNetwork.cs b/Dalamud/Game/Network/GameNetwork.cs deleted file mode 100644 index b8c91b235..000000000 --- a/Dalamud/Game/Network/GameNetwork.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System.Runtime.InteropServices; - -using Dalamud.Configuration.Internal; -using Dalamud.Hooking; -using Dalamud.Utility; - -using FFXIVClientStructs.FFXIV.Client.Network; - -using Serilog; - -namespace Dalamud.Game.Network; - -/// -/// This class handles interacting with game network events. -/// -[ServiceManager.EarlyLoadedService] -internal sealed unsafe class GameNetwork : IInternalDisposableService -{ - private readonly GameNetworkAddressResolver address; - private readonly Hook processZonePacketDownHook; - private readonly Hook processZonePacketUpHook; - - private readonly HitchDetector hitchDetectorUp; - private readonly HitchDetector hitchDetectorDown; - - [ServiceManager.ServiceDependency] - private readonly DalamudConfiguration configuration = Service.Get(); - - [ServiceManager.ServiceConstructor] - private unsafe GameNetwork(TargetSigScanner sigScanner) - { - this.hitchDetectorUp = new HitchDetector("GameNetworkUp", this.configuration.GameNetworkUpHitch); - this.hitchDetectorDown = new HitchDetector("GameNetworkDown", this.configuration.GameNetworkDownHitch); - - this.address = new GameNetworkAddressResolver(); - this.address.Setup(sigScanner); - - var onReceivePacketAddress = (nint)PacketDispatcher.StaticVirtualTablePointer->OnReceivePacket; - - Log.Verbose("===== G A M E N E T W O R K ====="); - Log.Verbose($"OnReceivePacket address {Util.DescribeAddress(onReceivePacketAddress)}"); - Log.Verbose($"ProcessZonePacketUp address {Util.DescribeAddress(this.address.ProcessZonePacketUp)}"); - - this.processZonePacketDownHook = Hook.FromAddress(onReceivePacketAddress, this.ProcessZonePacketDownDetour); - this.processZonePacketUpHook = Hook.FromAddress(this.address.ProcessZonePacketUp, this.ProcessZonePacketUpDetour); - - this.processZonePacketDownHook.Enable(); - this.processZonePacketUpHook.Enable(); - } - - /// - /// The delegate type of a network message event. - /// - /// The pointer to the raw data. - /// The operation ID code. - /// The source actor ID. - /// The taret actor ID. - /// The direction of the packed. - public delegate void OnNetworkMessageDelegate(nint dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction); - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - private delegate byte ProcessZonePacketUpDelegate(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4); - - /// - /// Event that is called when a network message is sent/received. - /// - public event OnNetworkMessageDelegate? NetworkMessage; - - /// - void IInternalDisposableService.DisposeService() - { - this.processZonePacketDownHook.Dispose(); - this.processZonePacketUpHook.Dispose(); - } - - private void ProcessZonePacketDownDetour(PacketDispatcher* dispatcher, uint targetId, IntPtr dataPtr) - { - this.hitchDetectorDown.Start(); - - // Go back 0x10 to get back to the start of the packet header - dataPtr -= 0x10; - - foreach (var d in Delegate.EnumerateInvocationList(this.NetworkMessage)) - { - try - { - d.Invoke( - dataPtr + 0x20, - (ushort)Marshal.ReadInt16(dataPtr, 0x12), - 0, - targetId, - NetworkMessageDirection.ZoneDown); - } - catch (Exception ex) - { - string header; - try - { - var data = new byte[32]; - Marshal.Copy(dataPtr, data, 0, 32); - header = BitConverter.ToString(data); - } - catch (Exception) - { - header = "failed"; - } - - Log.Error(ex, "Exception on ProcessZonePacketDown hook. Header: " + header); - } - } - - this.processZonePacketDownHook.Original(dispatcher, targetId, dataPtr + 0x10); - this.hitchDetectorDown.Stop(); - } - - private byte ProcessZonePacketUpDetour(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4) - { - this.hitchDetectorUp.Start(); - - try - { - // Call events - // TODO: Implement actor IDs - this.NetworkMessage?.Invoke(dataPtr + 0x20, (ushort)Marshal.ReadInt16(dataPtr), 0x0, 0x0, NetworkMessageDirection.ZoneUp); - } - catch (Exception ex) - { - string header; - try - { - var data = new byte[32]; - Marshal.Copy(dataPtr, data, 0, 32); - header = BitConverter.ToString(data); - } - catch (Exception) - { - header = "failed"; - } - - Log.Error(ex, "Exception on ProcessZonePacketUp hook. Header: " + header); - } - - this.hitchDetectorUp.Stop(); - - return this.processZonePacketUpHook.Original(a1, dataPtr, a3, a4); - } -} diff --git a/Dalamud/Game/Network/GameNetworkAddressResolver.cs b/Dalamud/Game/Network/GameNetworkAddressResolver.cs deleted file mode 100644 index 48abc2d97..000000000 --- a/Dalamud/Game/Network/GameNetworkAddressResolver.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Dalamud.Plugin.Services; - -namespace Dalamud.Game.Network; - -/// -/// The address resolver for the class. -/// -internal sealed class GameNetworkAddressResolver : BaseAddressResolver -{ - /// - /// Gets the address of the ProcessZonePacketUp method. - /// - public IntPtr ProcessZonePacketUp { get; private set; } - - /// - protected override void Setup64Bit(ISigScanner sig) - { - this.ProcessZonePacketUp = sig.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 4C 89 64 24 ?? 55 41 56 41 57 48 8B EC 48 83 EC 70"); // unnamed in cs - } -} diff --git a/Dalamud/Game/Network/Internal/NetworkHandlers.cs b/Dalamud/Game/Network/Internal/NetworkHandlers.cs index 5ca7da54a..d3a53b4f2 100644 --- a/Dalamud/Game/Network/Internal/NetworkHandlers.cs +++ b/Dalamud/Game/Network/Internal/NetworkHandlers.cs @@ -55,10 +55,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService private bool disposing; [ServiceManager.ServiceConstructor] - private NetworkHandlers( - GameNetwork gameNetwork, - TargetSigScanner sigScanner, - HappyHttpClient happyHttpClient) + private NetworkHandlers(TargetSigScanner sigScanner, HappyHttpClient happyHttpClient) { this.uploader = new UniversalisMarketBoardUploader(happyHttpClient); diff --git a/Dalamud/Game/Network/NetworkMessageDirection.cs b/Dalamud/Game/Network/NetworkMessageDirection.cs deleted file mode 100644 index 87cce5173..000000000 --- a/Dalamud/Game/Network/NetworkMessageDirection.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Dalamud.Game.Network; - -/// -/// This represents the direction of a network message. -/// -public enum NetworkMessageDirection -{ - /// - /// A zone down message. - /// - ZoneDown, - - /// - /// A zone up message. - /// - ZoneUp, -} diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs index ae173578a..922b72717 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs @@ -1,44 +1,51 @@ using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; +using System.Threading; using Dalamud.Bindings.ImGui; -using Dalamud.Game.Network; -using Dalamud.Interface.Utility; +using Dalamud.Game; +using Dalamud.Hooking; +using Dalamud.Interface.Components; using Dalamud.Interface.Utility.Raii; -using Dalamud.Memory; -using ImGuiTable = Dalamud.Interface.Utility.ImGuiTable; +using FFXIVClientStructs.FFXIV.Application.Network; +using FFXIVClientStructs.FFXIV.Client.Game; +using FFXIVClientStructs.FFXIV.Client.Game.Object; +using FFXIVClientStructs.FFXIV.Client.Game.UI; +using FFXIVClientStructs.FFXIV.Client.Network; namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// /// Widget to display the current packets. /// -internal class NetworkMonitorWidget : IDataWindowWidget +internal unsafe class NetworkMonitorWidget : IDataWindowWidget { private readonly ConcurrentQueue packets = new(); + private Hook? hookDown; + private Hook? hookUp; + private bool trackNetwork; - private int trackedPackets; - private Regex? trackedOpCodes; + private int trackedPackets = 20; + private ulong nextPacketIndex; private string filterString = string.Empty; - private Regex? untrackedOpCodes; - private string negativeFilterString = string.Empty; + private bool filterRecording = true; + private bool autoScroll = true; + private bool autoScrollPending; /// Finalizes an instance of the class. ~NetworkMonitorWidget() { - if (this.trackNetwork) - { - this.trackNetwork = false; - var network = Service.GetNullable(); - if (network != null) - { - network.NetworkMessage -= this.OnNetworkMessage; - } - } + this.hookDown?.Dispose(); + this.hookUp?.Dispose(); + } + + private delegate byte ZoneClientSendPacketDelegate(ZoneClient* thisPtr, nint packet, uint a3, uint a4, byte a5); + + private enum NetworkMessageDirection + { + ZoneDown, + ZoneUp, } /// @@ -53,31 +60,36 @@ internal class NetworkMonitorWidget : IDataWindowWidget /// public void Load() { - this.trackNetwork = false; - this.trackedPackets = 20; - this.trackedOpCodes = null; - this.filterString = string.Empty; - this.packets.Clear(); + this.hookDown = Hook.FromAddress( + (nint)PacketDispatcher.StaticVirtualTablePointer->OnReceivePacket, + this.OnReceivePacketDetour); + + // TODO: switch to ZoneClient.SendPacket from CS + if (Service.Get().TryScanText("E8 ?? ?? ?? ?? 4C 8B 44 24 ?? E9", out var address)) + this.hookUp = Hook.FromAddress(address, this.SendPacketDetour); + this.Ready = true; } /// public void Draw() { - var network = Service.Get(); if (ImGui.Checkbox("Track Network Packets"u8, ref this.trackNetwork)) { if (this.trackNetwork) { - network.NetworkMessage += this.OnNetworkMessage; + this.nextPacketIndex = 0; + this.hookDown?.Enable(); + this.hookUp?.Enable(); } else { - network.NetworkMessage -= this.OnNetworkMessage; + this.hookDown?.Disable(); + this.hookUp?.Disable(); } } - ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X / 2); + ImGui.SetNextItemWidth(-1); if (ImGui.DragInt("Stored Number of Packets"u8, ref this.trackedPackets, 0.1f, 1, 512)) { this.trackedPackets = Math.Clamp(this.trackedPackets, 1, 512); @@ -88,131 +100,200 @@ internal class NetworkMonitorWidget : IDataWindowWidget this.packets.Clear(); } - this.DrawFilterInput(); - this.DrawNegativeFilterInput(); + ImGui.SameLine(); + ImGui.Checkbox("Auto-Scroll"u8, ref this.autoScroll); - ImGuiTable.DrawTable(string.Empty, this.packets, this.DrawNetworkPacket, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg, "Direction", "OpCode", "Hex", "Target", "Source", "Data"); - } + ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X - (ImGui.GetStyle().ItemInnerSpacing.X + ImGui.GetFrameHeight()) * 2); + ImGui.InputTextWithHint("##Filter"u8, "Filter OpCodes..."u8, ref this.filterString, 1024, ImGuiInputTextFlags.AutoSelectAll); + ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); + ImGui.Checkbox("##FilterRecording"u8, ref this.filterRecording); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Apply filter to incoming packets.\nUncheck to record all packets and filter the table instead."u8); + ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); + ImGuiComponents.HelpMarker("Enter OpCodes in a comma-separated list.\nRanges are supported. Exclude OpCodes with exclamation mark.\nExample: -400,!50-100,650,700-980,!941"); - private void DrawNetworkPacket(NetworkPacketData data) - { - ImGui.TableNextColumn(); - ImGui.Text(data.Direction.ToString()); + using var table = ImRaii.Table("NetworkMonitorTableV2"u8, 6, ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg | ImGuiTableFlags.NoSavedSettings); + if (!table) return; - ImGui.TableNextColumn(); - ImGui.Text(data.OpCode.ToString()); + ImGui.TableSetupColumn("Index"u8, ImGuiTableColumnFlags.WidthFixed, 50); + ImGui.TableSetupColumn("Time"u8, ImGuiTableColumnFlags.WidthFixed, 100); + ImGui.TableSetupColumn("Direction"u8, ImGuiTableColumnFlags.WidthFixed, 100); + ImGui.TableSetupColumn("OpCode"u8, ImGuiTableColumnFlags.WidthFixed, 100); + ImGui.TableSetupColumn("OpCode (Hex)"u8, ImGuiTableColumnFlags.WidthFixed, 100); + ImGui.TableSetupColumn("Target EntityId"u8, ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupScrollFreeze(0, 1); + ImGui.TableHeadersRow(); - ImGui.TableNextColumn(); - ImGui.Text($"0x{data.OpCode:X4}"); + var autoScrollDisabled = false; - ImGui.TableNextColumn(); - ImGui.Text(data.TargetActorId > 0 ? $"0x{data.TargetActorId:X}" : string.Empty); - - ImGui.TableNextColumn(); - ImGui.Text(data.SourceActorId > 0 ? $"0x{data.SourceActorId:X}" : string.Empty); - - ImGui.TableNextColumn(); - if (data.Data.Count > 0) + foreach (var packet in this.packets) { - ImGui.Text(string.Join(" ", data.Data.Select(b => b.ToString("X2")))); + if (!this.filterRecording && !this.IsFiltered(packet.OpCode)) + continue; + + ImGui.TableNextColumn(); + ImGui.Text(packet.Index.ToString()); + + ImGui.TableNextColumn(); + ImGui.Text(packet.Time.ToLongTimeString()); + + ImGui.TableNextColumn(); + ImGui.Text(packet.Direction.ToString()); + + ImGui.TableNextColumn(); + using (ImRaii.PushId(packet.Index.ToString())) + { + if (ImGui.SmallButton("X")) + { + if (!string.IsNullOrEmpty(this.filterString)) + this.filterString += ","; + + this.filterString += $"!{packet.OpCode}"; + } + } + + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Filter OpCode"u8); + + autoScrollDisabled |= ImGui.IsItemHovered(); + + ImGui.SameLine(); + WidgetUtil.DrawCopyableText(packet.OpCode.ToString()); + autoScrollDisabled |= ImGui.IsItemHovered(); + + ImGui.TableNextColumn(); + WidgetUtil.DrawCopyableText($"0x{packet.OpCode:X3}"); + autoScrollDisabled |= ImGui.IsItemHovered(); + + ImGui.TableNextColumn(); + if (packet.TargetEntityId > 0) + { + WidgetUtil.DrawCopyableText($"{packet.TargetEntityId:X}"); + + var name = !string.IsNullOrEmpty(packet.TargetName) + ? packet.TargetName + : GetTargetName(packet.TargetEntityId); + + if (!string.IsNullOrEmpty(name)) + { + ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); + ImGui.Text($"({name})"); + } + } } - else + + if (this.autoScroll && this.autoScrollPending && !autoScrollDisabled) { - ImGui.Dummy(ImGui.GetContentRegionAvail() with { Y = 0 }); + ImGui.SetScrollHereY(); + this.autoScrollPending = false; } } - private void DrawFilterInput() + private static string GetTargetName(uint targetId) { - var invalidRegEx = this.filterString.Length > 0 && this.trackedOpCodes == null; - using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, invalidRegEx); - using var color = ImRaii.PushColor(ImGuiCol.Border, 0xFF0000FF, invalidRegEx); - ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); - if (!ImGui.InputTextWithHint("##Filter"u8, "Regex Filter OpCodes..."u8, ref this.filterString, 1024)) - { + if (targetId == PlayerState.Instance()->EntityId) + return "Local Player"; + + var cachedName = NameCache.Instance()->GetNameByEntityId(targetId); + if (cachedName.HasValue) + return cachedName.ToString(); + + var obj = GameObjectManager.Instance()->Objects.GetObjectByEntityId(targetId); + if (obj != null) + return obj->NameString; + + return string.Empty; + } + + private void OnReceivePacketDetour(PacketDispatcher* thisPtr, uint targetId, nint packet) + { + var opCode = *(ushort*)(packet + 2); + var targetName = GetTargetName(targetId); + this.RecordPacket(new NetworkPacketData(Interlocked.Increment(ref this.nextPacketIndex), DateTime.Now, opCode, NetworkMessageDirection.ZoneDown, targetId, targetName)); + this.hookDown.OriginalDisposeSafe(thisPtr, targetId, packet); + } + + private byte SendPacketDetour(ZoneClient* thisPtr, nint packet, uint a3, uint a4, byte a5) + { + var opCode = *(ushort*)packet; + this.RecordPacket(new NetworkPacketData(Interlocked.Increment(ref this.nextPacketIndex), DateTime.Now, opCode, NetworkMessageDirection.ZoneUp, 0, string.Empty)); + return this.hookUp.OriginalDisposeSafe(thisPtr, packet, a3, a4, a5); + } + + private void RecordPacket(NetworkPacketData packet) + { + if (this.filterRecording && !this.IsFiltered(packet.OpCode)) return; + + this.packets.Enqueue(packet); + + while (this.packets.Count > this.trackedPackets) + { + this.packets.TryDequeue(out _); } - if (this.filterString.Length == 0) - { - this.trackedOpCodes = null; - } - else - { - try - { - this.trackedOpCodes = new Regex(this.filterString, RegexOptions.Compiled | RegexOptions.ExplicitCapture); - } - catch - { - this.trackedOpCodes = null; - } - } + this.autoScrollPending = true; } - private void DrawNegativeFilterInput() + private bool IsFiltered(ushort opcode) { - var invalidRegEx = this.negativeFilterString.Length > 0 && this.untrackedOpCodes == null; - using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, invalidRegEx); - using var color = ImRaii.PushColor(ImGuiCol.Border, 0xFF0000FF, invalidRegEx); - ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); - if (!ImGui.InputTextWithHint("##NegativeFilter"u8, "Regex Filter Against OpCodes..."u8, ref this.negativeFilterString, 1024)) - { - return; - } + var filterString = this.filterString.Replace(" ", string.Empty); - if (this.negativeFilterString.Length == 0) + if (filterString.Length == 0) + return true; + + try { - this.untrackedOpCodes = null; + var offset = 0; + var included = false; + var hasInclude = false; + + while (filterString.Length - offset > 0) + { + var remaining = filterString[offset..]; + + // find the end of the current entry + var entryEnd = remaining.IndexOf(','); + if (entryEnd == -1) + entryEnd = remaining.Length; + + var entry = filterString[offset..(offset + entryEnd)]; + var dash = entry.IndexOf('-'); + var isExcluded = entry.StartsWith('!'); + var startOffset = isExcluded ? 1 : 0; + + var entryMatch = dash == -1 + ? ushort.Parse(entry[startOffset..]) == opcode + : ((dash - startOffset == 0 || opcode >= ushort.Parse(entry[startOffset..dash])) + && (entry[(dash + 1)..].Length == 0 || opcode <= ushort.Parse(entry[(dash + 1)..]))); + + if (isExcluded) + { + if (entryMatch) + return false; + } + else + { + hasInclude = true; + included |= entryMatch; + } + + if (entryEnd == filterString.Length) + break; + + offset += entryEnd + 1; + } + + return !hasInclude || included; } - else + catch (Exception ex) { - try - { - this.untrackedOpCodes = new Regex(this.negativeFilterString, RegexOptions.Compiled | RegexOptions.ExplicitCapture); - } - catch - { - this.untrackedOpCodes = null; - } + Serilog.Log.Error(ex, "Invalid filter string"); + return false; } } - private void OnNetworkMessage(nint dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction) - { - if ((this.trackedOpCodes == null || this.trackedOpCodes.IsMatch(this.OpCodeToString(opCode))) - && (this.untrackedOpCodes == null || !this.untrackedOpCodes.IsMatch(this.OpCodeToString(opCode)))) - { - this.packets.Enqueue(new NetworkPacketData(this, opCode, direction, sourceActorId, targetActorId, dataPtr)); - while (this.packets.Count > this.trackedPackets) - { - this.packets.TryDequeue(out _); - } - } - } - - private int GetSizeFromOpCode(ushort opCode) - => 0; - - /// Add known packet-name -> packet struct size associations here to copy the byte data for such packets. > - private int GetSizeFromName(string name) - => name switch - { - _ => 0, - }; - - /// The filter should find opCodes by number (decimal and hex) and name, if existing. - private string OpCodeToString(ushort opCode) - => $"{opCode}\0{opCode:X}"; - #pragma warning disable SA1313 - private readonly record struct NetworkPacketData(ushort OpCode, NetworkMessageDirection Direction, uint SourceActorId, uint TargetActorId) + private readonly record struct NetworkPacketData(ulong Index, DateTime Time, ushort OpCode, NetworkMessageDirection Direction, uint TargetEntityId, string TargetName); #pragma warning restore SA1313 - { - public readonly IReadOnlyList Data = []; - - public NetworkPacketData(NetworkMonitorWidget widget, ushort opCode, NetworkMessageDirection direction, uint sourceActorId, uint targetActorId, nint dataPtr) - : this(opCode, direction, sourceActorId, targetActorId) - => this.Data = MemoryHelper.Read(dataPtr, widget.GetSizeFromOpCode(opCode), false); - } } diff --git a/Dalamud/Plugin/Services/IGameNetwork.cs b/Dalamud/Plugin/Services/IGameNetwork.cs deleted file mode 100644 index 4abf20834..000000000 --- a/Dalamud/Plugin/Services/IGameNetwork.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Dalamud.Game.Network; - -namespace Dalamud.Plugin.Services; - -/// -/// This class handles interacting with game network events. -/// -[Obsolete("Will be removed in a future release. Use packet handler hooks instead.", true)] -public interface IGameNetwork : IDalamudService -{ - // TODO(v9): we shouldn't be passing pointers to the actual data here - - /// - /// The delegate type of a network message event. - /// - /// The pointer to the raw data. - /// The operation ID code. - /// The source actor ID. - /// The taret actor ID. - /// The direction of the packed. - public delegate void OnNetworkMessageDelegate(nint dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction); - - /// - /// Event that is called when a network message is sent/received. - /// - public event OnNetworkMessageDelegate NetworkMessage; -} From 5da79a7dbaa88a3c5695ec54b5882e19f393a5dc Mon Sep 17 00:00:00 2001 From: Limiana <5073202+Limiana@users.noreply.github.com> Date: Tue, 27 Jan 2026 19:38:42 +0300 Subject: [PATCH 64/99] Use RowRef in ZoneInitEventArgs (#2540) * Try-catch packet read * Actually use RowRef instead --- Dalamud/Game/ClientState/ZoneInit.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Dalamud/Game/ClientState/ZoneInit.cs b/Dalamud/Game/ClientState/ZoneInit.cs index 7eb4576aa..7d6cda90f 100644 --- a/Dalamud/Game/ClientState/ZoneInit.cs +++ b/Dalamud/Game/ClientState/ZoneInit.cs @@ -3,8 +3,11 @@ using System.Text; using Dalamud.Data; +using Lumina.Excel; using Lumina.Excel.Sheets; +using Serilog; + namespace Dalamud.Game.ClientState; /// @@ -15,7 +18,7 @@ public class ZoneInitEventArgs : EventArgs /// /// Gets the territory type of the zone being entered. /// - public TerritoryType TerritoryType { get; private set; } + public RowRef TerritoryType { get; private set; } /// /// Gets the instance number of the zone, used when multiple copies of an area are active. @@ -25,17 +28,17 @@ public class ZoneInitEventArgs : EventArgs /// /// Gets the associated content finder condition for the zone, if any. /// - public ContentFinderCondition ContentFinderCondition { get; private set; } + public RowRef ContentFinderCondition { get; private set; } /// /// Gets the current weather in the zone upon entry. /// - public Weather Weather { get; private set; } + public RowRef Weather { get; private set; } /// /// Gets the set of active festivals in the zone. /// - public Festival[] ActiveFestivals { get; private set; } = []; + public RowRef[] ActiveFestivals { get; private set; } = []; /// /// Gets the phases corresponding to the active festivals. @@ -54,20 +57,20 @@ public class ZoneInitEventArgs : EventArgs var flags = *(byte*)(packet + 0x12); - eventArgs.TerritoryType = dataManager.GetExcelSheet().GetRow(*(ushort*)(packet + 0x02)); + eventArgs.TerritoryType = LuminaUtils.CreateRef(*(ushort*)(packet + 0x02)); eventArgs.Instance = flags >= 0 ? (ushort)0 : *(ushort*)(packet + 0x04); - eventArgs.ContentFinderCondition = dataManager.GetExcelSheet().GetRow(*(ushort*)(packet + 0x06)); - eventArgs.Weather = dataManager.GetExcelSheet().GetRow(*(byte*)(packet + 0x10)); + eventArgs.ContentFinderCondition = LuminaUtils.CreateRef(*(ushort*)(packet + 0x06)); + eventArgs.Weather = LuminaUtils.CreateRef(*(byte*)(packet + 0x10)); const int NumFestivals = 8; - eventArgs.ActiveFestivals = new Festival[NumFestivals]; + eventArgs.ActiveFestivals = new RowRef[NumFestivals]; eventArgs.ActiveFestivalPhases = new ushort[NumFestivals]; // There are also 4 festival ids and phases for PlayerState at +0x3E and +0x46 respectively, // but it's unclear why they exist as separate entries and why they would be different. for (var i = 0; i < NumFestivals; i++) { - eventArgs.ActiveFestivals[i] = dataManager.GetExcelSheet().GetRow(*(ushort*)(packet + 0x26 + (i * 2))); + eventArgs.ActiveFestivals[i] = LuminaUtils.CreateRef(*(ushort*)(packet + 0x26 + (i * 2))); eventArgs.ActiveFestivalPhases[i] = *(ushort*)(packet + 0x36 + (i * 2)); } From 10ef40ddf5651404470d9da0511fd55c5b4c4f1f Mon Sep 17 00:00:00 2001 From: bleatbot <106497096+bleatbot@users.noreply.github.com> Date: Tue, 27 Jan 2026 17:42:07 +0100 Subject: [PATCH 65/99] Update ClientStructs (#2595) Co-authored-by: github-actions[bot] --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 127047085..a02536a4b 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 1270470855d6ac2d2f726b07019e21644c5658ec +Subproject commit a02536a4bf6862036403c03945a02fcd6689e445 From c0077b1e260a34e3e2f36ab8d4bd1b08aa9623d2 Mon Sep 17 00:00:00 2001 From: KazWolfe Date: Tue, 27 Jan 2026 09:30:34 -0800 Subject: [PATCH 66/99] Revert "Use RowRef in ZoneInitEventArgs (#2540)" (#2597) This reverts commit 5da79a7dbaa88a3c5695ec54b5882e19f393a5dc. --- Dalamud/Game/ClientState/ZoneInit.cs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/Dalamud/Game/ClientState/ZoneInit.cs b/Dalamud/Game/ClientState/ZoneInit.cs index 7d6cda90f..7eb4576aa 100644 --- a/Dalamud/Game/ClientState/ZoneInit.cs +++ b/Dalamud/Game/ClientState/ZoneInit.cs @@ -3,11 +3,8 @@ using System.Text; using Dalamud.Data; -using Lumina.Excel; using Lumina.Excel.Sheets; -using Serilog; - namespace Dalamud.Game.ClientState; /// @@ -18,7 +15,7 @@ public class ZoneInitEventArgs : EventArgs /// /// Gets the territory type of the zone being entered. /// - public RowRef TerritoryType { get; private set; } + public TerritoryType TerritoryType { get; private set; } /// /// Gets the instance number of the zone, used when multiple copies of an area are active. @@ -28,17 +25,17 @@ public class ZoneInitEventArgs : EventArgs /// /// Gets the associated content finder condition for the zone, if any. /// - public RowRef ContentFinderCondition { get; private set; } + public ContentFinderCondition ContentFinderCondition { get; private set; } /// /// Gets the current weather in the zone upon entry. /// - public RowRef Weather { get; private set; } + public Weather Weather { get; private set; } /// /// Gets the set of active festivals in the zone. /// - public RowRef[] ActiveFestivals { get; private set; } = []; + public Festival[] ActiveFestivals { get; private set; } = []; /// /// Gets the phases corresponding to the active festivals. @@ -57,20 +54,20 @@ public class ZoneInitEventArgs : EventArgs var flags = *(byte*)(packet + 0x12); - eventArgs.TerritoryType = LuminaUtils.CreateRef(*(ushort*)(packet + 0x02)); + eventArgs.TerritoryType = dataManager.GetExcelSheet().GetRow(*(ushort*)(packet + 0x02)); eventArgs.Instance = flags >= 0 ? (ushort)0 : *(ushort*)(packet + 0x04); - eventArgs.ContentFinderCondition = LuminaUtils.CreateRef(*(ushort*)(packet + 0x06)); - eventArgs.Weather = LuminaUtils.CreateRef(*(byte*)(packet + 0x10)); + eventArgs.ContentFinderCondition = dataManager.GetExcelSheet().GetRow(*(ushort*)(packet + 0x06)); + eventArgs.Weather = dataManager.GetExcelSheet().GetRow(*(byte*)(packet + 0x10)); const int NumFestivals = 8; - eventArgs.ActiveFestivals = new RowRef[NumFestivals]; + eventArgs.ActiveFestivals = new Festival[NumFestivals]; eventArgs.ActiveFestivalPhases = new ushort[NumFestivals]; // There are also 4 festival ids and phases for PlayerState at +0x3E and +0x46 respectively, // but it's unclear why they exist as separate entries and why they would be different. for (var i = 0; i < NumFestivals; i++) { - eventArgs.ActiveFestivals[i] = LuminaUtils.CreateRef(*(ushort*)(packet + 0x26 + (i * 2))); + eventArgs.ActiveFestivals[i] = dataManager.GetExcelSheet().GetRow(*(ushort*)(packet + 0x26 + (i * 2))); eventArgs.ActiveFestivalPhases[i] = *(ushort*)(packet + 0x36 + (i * 2)); } From e598013e304b993a1ff079325cd62efb69292f23 Mon Sep 17 00:00:00 2001 From: goaaats Date: Tue, 27 Jan 2026 18:53:35 +0100 Subject: [PATCH 67/99] Upgrade goatcorp.Reloaded.Hooks, remove goatcorp.Reloaded.Assembler --- Dalamud/Dalamud.csproj | 1 - Directory.Packages.props | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 287bc5322..a1a08a908 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -65,7 +65,6 @@ - diff --git a/Directory.Packages.props b/Directory.Packages.props index 18760037b..2a8c52dc4 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -41,8 +41,7 @@ - - + From 5c7a5295d119c65510f9cc0b3fb4b8c4e418ea20 Mon Sep 17 00:00:00 2001 From: MidoriKami <9083275+MidoriKami@users.noreply.github.com> Date: Tue, 27 Jan 2026 13:49:35 -0800 Subject: [PATCH 68/99] Misc Fixes (#2584) * Disable default logging, remove log message * Add IDtrBarEntry.MinimumWidth * Fix Addon/Agent Lifecycle Register/Unregister * Rename Agent.ReceiveEvent2 * Add to IReadOnlyDtrBarEntry * Fix autoformat being terrible * More style fixes * Add focused changed lifecycle event * Fix for obsolete renames --- .../AddonArgTypes/AddonFocusChangedArgs.cs | 22 ++++ Dalamud/Game/Addon/Lifecycle/AddonArgsType.cs | 5 + Dalamud/Game/Addon/Lifecycle/AddonEvent.cs | 10 ++ .../Game/Addon/Lifecycle/AddonLifecycle.cs | 97 ++++++++++------ .../Game/Addon/Lifecycle/AddonVirtualTable.cs | 34 ++++++ Dalamud/Game/Agent/AgentEvent.cs | 4 +- Dalamud/Game/Agent/AgentLifecycle.cs | 105 +++++++++++------- Dalamud/Game/Agent/AgentVirtualTable.cs | 20 ++-- Dalamud/Game/Gui/Dtr/DtrBar.cs | 10 +- Dalamud/Game/Gui/Dtr/DtrBarEntry.cs | 29 +++++ 10 files changed, 245 insertions(+), 91 deletions(-) create mode 100644 Dalamud/Game/Addon/Lifecycle/AddonArgTypes/AddonFocusChangedArgs.cs diff --git a/Dalamud/Game/Addon/Lifecycle/AddonArgTypes/AddonFocusChangedArgs.cs b/Dalamud/Game/Addon/Lifecycle/AddonArgTypes/AddonFocusChangedArgs.cs new file mode 100644 index 000000000..8936a233b --- /dev/null +++ b/Dalamud/Game/Addon/Lifecycle/AddonArgTypes/AddonFocusChangedArgs.cs @@ -0,0 +1,22 @@ +namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes; + +/// +/// Addon argument data for OnFocusChanged events. +/// +public class AddonFocusChangedArgs : AddonArgs +{ + /// + /// Initializes a new instance of the class. + /// + internal AddonFocusChangedArgs() + { + } + + /// + public override AddonArgsType Type => AddonArgsType.FocusChanged; + + /// + /// Gets or sets a value indicating whether the window is being focused or unfocused. + /// + public bool ShouldFocus { get; set; } +} diff --git a/Dalamud/Game/Addon/Lifecycle/AddonArgsType.cs b/Dalamud/Game/Addon/Lifecycle/AddonArgsType.cs index 46ee479ac..bc48eeed0 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonArgsType.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonArgsType.cs @@ -44,4 +44,9 @@ public enum AddonArgsType /// Contains argument data for Close. /// Close, + + /// + /// Contains argument data for OnFocusChanged. + /// + FocusChanged, } diff --git a/Dalamud/Game/Addon/Lifecycle/AddonEvent.cs b/Dalamud/Game/Addon/Lifecycle/AddonEvent.cs index 3b9c6e867..74c84d754 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonEvent.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonEvent.cs @@ -203,4 +203,14 @@ public enum AddonEvent /// Be aware this is only called for certain popup windows, it is not triggered when clicking on windows. /// PostFocus, + + /// + /// An event that is fired before an addon processes its FocusChanged method. + /// + PreFocusChanged, + + /// + /// An event that is fired after a addon processes its FocusChanged method. + /// + PostFocusChanged, } diff --git a/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs b/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs index c70c0c10f..6520ee4cf 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonLifecycle.cs @@ -31,7 +31,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService private readonly Framework framework = Service.Get(); private Hook? onInitializeAddonHook; - private bool isInvokingListeners = false; + private bool isInvokingListeners; [ServiceManager.ServiceConstructor] private AddonLifecycle() @@ -56,29 +56,36 @@ internal unsafe class AddonLifecycle : IInternalDisposableService AllocatedTables.Clear(); } + /// + /// Resolves a virtual table address to the original virtual table address. + /// + /// The modified address to resolve. + /// The original address. + internal static AtkUnitBase.AtkUnitBaseVirtualTable* GetOriginalVirtualTable(AtkUnitBase.AtkUnitBaseVirtualTable* tableAddress) + { + var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress); + if (matchedTable == null) + { + return null; + } + + return matchedTable.OriginalVirtualTable; + } + /// /// Register a listener for the target event and addon. /// /// The listener to register. internal void RegisterListener(AddonLifecycleEventListener listener) { - this.framework.RunOnTick(() => + if (this.isInvokingListeners) { - if (!this.EventListeners.ContainsKey(listener.EventType)) - { - if (!this.EventListeners.TryAdd(listener.EventType, [])) - return; - } - - // Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type - if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName)) - { - if (!this.EventListeners[listener.EventType].TryAdd(listener.AddonName, [])) - return; - } - - this.EventListeners[listener.EventType][listener.AddonName].Add(listener); - }, delayTicks: this.isInvokingListeners ? 1 : 0); + this.framework.RunOnTick(() => this.RegisterListenerMethod(listener)); + } + else + { + this.framework.RunOnFrameworkThread(() => this.RegisterListenerMethod(listener)); + } } /// @@ -87,16 +94,14 @@ internal unsafe class AddonLifecycle : IInternalDisposableService /// The listener to unregister. internal void UnregisterListener(AddonLifecycleEventListener listener) { - this.framework.RunOnTick(() => + if (this.isInvokingListeners) { - if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners)) - { - if (addonListeners.TryGetValue(listener.AddonName, out var addonListener)) - { - addonListener.Remove(listener); - } - } - }, delayTicks: this.isInvokingListeners ? 1 : 0); + this.framework.RunOnTick(() => this.UnregisterListenerMethod(listener)); + } + else + { + this.framework.RunOnFrameworkThread(() => this.UnregisterListenerMethod(listener)); + } } /// @@ -147,17 +152,37 @@ internal unsafe class AddonLifecycle : IInternalDisposableService this.isInvokingListeners = false; } - /// - /// Resolves a virtual table address to the original virtual table address. - /// - /// The modified address to resolve. - /// The original address. - internal AtkUnitBase.AtkUnitBaseVirtualTable* GetOriginalVirtualTable(AtkUnitBase.AtkUnitBaseVirtualTable* tableAddress) + private void RegisterListenerMethod(AddonLifecycleEventListener listener) { - var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress); - if (matchedTable == null) return null; + if (!this.EventListeners.ContainsKey(listener.EventType)) + { + if (!this.EventListeners.TryAdd(listener.EventType, [])) + { + return; + } + } - return matchedTable.OriginalVirtualTable; + // Note: string.Empty is a valid addon name, as that will trigger on any addon for this event type + if (!this.EventListeners[listener.EventType].ContainsKey(listener.AddonName)) + { + if (!this.EventListeners[listener.EventType].TryAdd(listener.AddonName, [])) + { + return; + } + } + + this.EventListeners[listener.EventType][listener.AddonName].Add(listener); + } + + private void UnregisterListenerMethod(AddonLifecycleEventListener listener) + { + if (this.EventListeners.TryGetValue(listener.EventType, out var addonListeners)) + { + if (addonListeners.TryGetValue(listener.AddonName, out var addonListener)) + { + addonListener.Remove(listener); + } + } } private void OnAddonInitialize(AtkUnitBase* addon) @@ -277,5 +302,5 @@ internal class AddonLifecyclePluginScoped : IInternalDisposableService, IAddonLi /// public unsafe nint GetOriginalVirtualTable(nint virtualTableAddress) - => (nint)this.addonLifecycleService.GetOriginalVirtualTable((AtkUnitBase.AtkUnitBaseVirtualTable*)virtualTableAddress); + => (nint)AddonLifecycle.GetOriginalVirtualTable((AtkUnitBase.AtkUnitBaseVirtualTable*)virtualTableAddress); } diff --git a/Dalamud/Game/Addon/Lifecycle/AddonVirtualTable.cs b/Dalamud/Game/Addon/Lifecycle/AddonVirtualTable.cs index 736415738..1b2c828f8 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonVirtualTable.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonVirtualTable.cs @@ -42,6 +42,7 @@ internal unsafe class AddonVirtualTable : IDisposable private readonly AddonArgs onMouseOverArgs = new(); private readonly AddonArgs onMouseOutArgs = new(); private readonly AddonArgs focusArgs = new(); + private readonly AddonFocusChangedArgs focusChangedArgs = new(); private readonly AtkUnitBase* atkUnitBase; @@ -63,6 +64,7 @@ internal unsafe class AddonVirtualTable : IDisposable private readonly AtkUnitBase.Delegates.OnMouseOver onMouseOverFunction; private readonly AtkUnitBase.Delegates.OnMouseOut onMouseOutFunction; private readonly AtkUnitBase.Delegates.Focus focusFunction; + private readonly AtkUnitBase.Delegates.OnFocusChange onFocusChangeFunction; /// /// Initializes a new instance of the class. @@ -103,6 +105,7 @@ internal unsafe class AddonVirtualTable : IDisposable this.onMouseOverFunction = this.OnAddonMouseOver; this.onMouseOutFunction = this.OnAddonMouseOut; this.focusFunction = this.OnAddonFocus; + this.onFocusChangeFunction = this.OnAddonFocusChange; // Overwrite specific virtual table entries this.ModifiedVirtualTable->Dtor = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.destructorFunction); @@ -121,6 +124,7 @@ internal unsafe class AddonVirtualTable : IDisposable this.ModifiedVirtualTable->OnMouseOver = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.onMouseOverFunction); this.ModifiedVirtualTable->OnMouseOut = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.onMouseOutFunction); this.ModifiedVirtualTable->Focus = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.focusFunction); + this.ModifiedVirtualTable->OnFocusChange = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.onFocusChangeFunction); } /// @@ -630,6 +634,36 @@ internal unsafe class AddonVirtualTable : IDisposable } } + private void OnAddonFocusChange(AtkUnitBase* thisPtr, bool isFocused) + { + try + { + this.LogEvent(EnableLogging); + + this.focusChangedArgs.Addon = thisPtr; + this.focusChangedArgs.ShouldFocus = isFocused; + + this.lifecycleService.InvokeListenersSafely(AddonEvent.PreFocusChanged, this.focusChangedArgs); + + isFocused = this.focusChangedArgs.ShouldFocus; + + try + { + this.OriginalVirtualTable->OnFocusChange(thisPtr, isFocused); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Addon OnFocusChanged. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AddonEvent.PostFocusChanged, this.focusChangedArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAddonFocusChange."); + } + } + [Conditional("DEBUG")] private void LogEvent(bool loggingEnabled, [CallerMemberName] string caller = "") { diff --git a/Dalamud/Game/Agent/AgentEvent.cs b/Dalamud/Game/Agent/AgentEvent.cs index 2a3002daa..e9c9a1b85 100644 --- a/Dalamud/Game/Agent/AgentEvent.cs +++ b/Dalamud/Game/Agent/AgentEvent.cs @@ -18,12 +18,12 @@ public enum AgentEvent /// /// An event that is fired before the agent processes its Filtered Receive Event Function. /// - PreReceiveFilteredEvent, + PreReceiveEventWithResult, /// /// An event that is fired after the agent has processed its Filtered Receive Event Function. /// - PostReceiveFilteredEvent, + PostReceiveEventWithResult, /// /// An event that is fired before the agent processes its Show Function. diff --git a/Dalamud/Game/Agent/AgentLifecycle.cs b/Dalamud/Game/Agent/AgentLifecycle.cs index 75ed47d86..45f0dec5c 100644 --- a/Dalamud/Game/Agent/AgentLifecycle.cs +++ b/Dalamud/Game/Agent/AgentLifecycle.cs @@ -69,30 +69,36 @@ internal unsafe class AgentLifecycle : IInternalDisposableService AllocatedTables.Clear(); } + /// + /// Resolves a virtual table address to the original virtual table address. + /// + /// The modified address to resolve. + /// The original address. + internal static AgentInterface.AgentInterfaceVirtualTable* GetOriginalVirtualTable(AgentInterface.AgentInterfaceVirtualTable* tableAddress) + { + var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress); + if (matchedTable == null) + { + return null; + } + + return matchedTable.OriginalVirtualTable; + } + /// /// Register a listener for the target event and agent. /// /// The listener to register. internal void RegisterListener(AgentLifecycleEventListener listener) { - this.framework.RunOnTick(() => + if (this.isInvokingListeners) { - if (!this.EventListeners.ContainsKey(listener.EventType)) - { - if (!this.EventListeners.TryAdd(listener.EventType, [])) - return; - } - - // Note: uint.MaxValue is a valid agent id, as that will trigger on any agent for this event type - if (!this.EventListeners[listener.EventType].ContainsKey(listener.AgentId)) - { - if (!this.EventListeners[listener.EventType].TryAdd(listener.AgentId, [])) - return; - } - - this.EventListeners[listener.EventType][listener.AgentId].Add(listener); - }, - delayTicks: this.isInvokingListeners ? 1 : 0); + this.framework.RunOnTick(() => this.RegisterListenerMethod(listener)); + } + else + { + this.framework.RunOnFrameworkThread(() => this.RegisterListenerMethod(listener)); + } } /// @@ -101,17 +107,14 @@ internal unsafe class AgentLifecycle : IInternalDisposableService /// The listener to unregister. internal void UnregisterListener(AgentLifecycleEventListener listener) { - this.framework.RunOnTick(() => + if (this.isInvokingListeners) { - if (this.EventListeners.TryGetValue(listener.EventType, out var agentListeners)) - { - if (agentListeners.TryGetValue(listener.AgentId, out var agentListener)) - { - agentListener.Remove(listener); - } - } - }, - delayTicks: this.isInvokingListeners ? 1 : 0); + this.framework.RunOnTick(() => this.UnregisterListenerMethod(listener)); + } + else + { + this.framework.RunOnFrameworkThread(() => this.UnregisterListenerMethod(listener)); + } } /// @@ -162,19 +165,6 @@ internal unsafe class AgentLifecycle : IInternalDisposableService this.isInvokingListeners = false; } - /// - /// Resolves a virtual table address to the original virtual table address. - /// - /// The modified address to resolve. - /// The original address. - internal AgentInterface.AgentInterfaceVirtualTable* GetOriginalVirtualTable(AgentInterface.AgentInterfaceVirtualTable* tableAddress) - { - var matchedTable = AllocatedTables.FirstOrDefault(table => table.ModifiedVirtualTable == tableAddress); - if (matchedTable == null) return null; - - return matchedTable.OriginalVirtualTable; - } - private void OnAgentModuleInitialize(AgentModule* thisPtr, UIModule* uiModule) { this.onInitializeAgentsHook!.Original(thisPtr, uiModule); @@ -193,6 +183,39 @@ internal unsafe class AgentLifecycle : IInternalDisposableService } } + private void RegisterListenerMethod(AgentLifecycleEventListener listener) + { + if (!this.EventListeners.ContainsKey(listener.EventType)) + { + if (!this.EventListeners.TryAdd(listener.EventType, [])) + { + return; + } + } + + // Note: uint.MaxValue is a valid agent id, as that will trigger on any agent for this event type + if (!this.EventListeners[listener.EventType].ContainsKey(listener.AgentId)) + { + if (!this.EventListeners[listener.EventType].TryAdd(listener.AgentId, [])) + { + return; + } + } + + this.EventListeners[listener.EventType][listener.AgentId].Add(listener); + } + + private void UnregisterListenerMethod(AgentLifecycleEventListener listener) + { + if (this.EventListeners.TryGetValue(listener.EventType, out var agentListeners)) + { + if (agentListeners.TryGetValue(listener.AgentId, out var agentListener)) + { + agentListener.Remove(listener); + } + } + } + private void ReplaceVirtualTables(AgentModule* agentModule) { foreach (uint index in Enumerable.Range(0, agentModule->Agents.Length)) @@ -311,5 +334,5 @@ internal class AgentLifecyclePluginScoped : IInternalDisposableService, IAgentLi /// public unsafe nint GetOriginalVirtualTable(nint virtualTableAddress) - => (nint)this.agentLifecycleService.GetOriginalVirtualTable((AgentInterface.AgentInterfaceVirtualTable*)virtualTableAddress); + => (nint)AgentLifecycle.GetOriginalVirtualTable((AgentInterface.AgentInterfaceVirtualTable*)virtualTableAddress); } diff --git a/Dalamud/Game/Agent/AgentVirtualTable.cs b/Dalamud/Game/Agent/AgentVirtualTable.cs index e7f9a2f6e..99f613137 100644 --- a/Dalamud/Game/Agent/AgentVirtualTable.cs +++ b/Dalamud/Game/Agent/AgentVirtualTable.cs @@ -21,7 +21,7 @@ internal unsafe class AgentVirtualTable : IDisposable // Copying extra entries is not problematic, and is considered safe. private const int VirtualTableEntryCount = 60; - private const bool EnableLogging = true; + private const bool EnableLogging = false; private static readonly ModuleLog Log = new("AgentVT"); @@ -44,7 +44,7 @@ internal unsafe class AgentVirtualTable : IDisposable // Pinned Function Delegates, as these functions get assigned to an unmanaged virtual table, // the CLR needs to know they are in use, or it will invalidate them causing random crashing. private readonly AgentInterface.Delegates.ReceiveEvent receiveEventFunction; - private readonly AgentInterface.Delegates.ReceiveEvent2 filteredReceiveEventFunction; + private readonly AgentInterface.Delegates.ReceiveEventWithResult receiveEventWithResultFunction; private readonly AgentInterface.Delegates.Show showFunction; private readonly AgentInterface.Delegates.Hide hideFunction; private readonly AgentInterface.Delegates.Update updateFunction; @@ -60,8 +60,6 @@ internal unsafe class AgentVirtualTable : IDisposable /// Reference to AgentLifecycle service to callback and invoke listeners. internal AgentVirtualTable(AgentInterface* agent, AgentId agentId, AgentLifecycle lifecycleService) { - Log.Debug($"Initializing AgentVirtualTable for {agentId}, Address: {(nint)agent:X}"); - this.agentInterface = agent; this.agentId = agentId; this.lifecycleService = lifecycleService; @@ -80,7 +78,7 @@ internal unsafe class AgentVirtualTable : IDisposable // Pin each of our listener functions this.receiveEventFunction = this.OnAgentReceiveEvent; - this.filteredReceiveEventFunction = this.OnAgentFilteredReceiveEvent; + this.receiveEventWithResultFunction = this.OnAgentReceiveEventWithResult; this.showFunction = this.OnAgentShow; this.hideFunction = this.OnAgentHide; this.updateFunction = this.OnAgentUpdate; @@ -90,7 +88,7 @@ internal unsafe class AgentVirtualTable : IDisposable // Overwrite specific virtual table entries this.ModifiedVirtualTable->ReceiveEvent = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.receiveEventFunction); - this.ModifiedVirtualTable->ReceiveEvent2 = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.filteredReceiveEventFunction); + this.ModifiedVirtualTable->ReceiveEventWithResult = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.receiveEventWithResultFunction); this.ModifiedVirtualTable->Show = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.showFunction); this.ModifiedVirtualTable->Hide = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.hideFunction); this.ModifiedVirtualTable->Update = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.updateFunction); @@ -158,7 +156,7 @@ internal unsafe class AgentVirtualTable : IDisposable return result; } - private AtkValue* OnAgentFilteredReceiveEvent(AgentInterface* thisPtr, AtkValue* returnValue, AtkValue* values, uint valueCount, ulong eventKind) + private AtkValue* OnAgentReceiveEventWithResult(AgentInterface* thisPtr, AtkValue* returnValue, AtkValue* values, uint valueCount, ulong eventKind) { AtkValue* result = null; @@ -173,7 +171,7 @@ internal unsafe class AgentVirtualTable : IDisposable this.filteredReceiveEventArgs.ValueCount = valueCount; this.filteredReceiveEventArgs.EventKind = eventKind; - this.lifecycleService.InvokeListenersSafely(AgentEvent.PreReceiveFilteredEvent, this.filteredReceiveEventArgs); + this.lifecycleService.InvokeListenersSafely(AgentEvent.PreReceiveEventWithResult, this.filteredReceiveEventArgs); returnValue = (AtkValue*)this.filteredReceiveEventArgs.ReturnValue; values = (AtkValue*)this.filteredReceiveEventArgs.AtkValues; @@ -182,18 +180,18 @@ internal unsafe class AgentVirtualTable : IDisposable try { - result = this.OriginalVirtualTable->ReceiveEvent2(thisPtr, returnValue, values, valueCount, eventKind); + result = this.OriginalVirtualTable->ReceiveEventWithResult(thisPtr, returnValue, values, valueCount, eventKind); } catch (Exception e) { Log.Error(e, "Caught exception when calling original Agent FilteredReceiveEvent. This may be a bug in the game or another plugin hooking this method."); } - this.lifecycleService.InvokeListenersSafely(AgentEvent.PostReceiveFilteredEvent, this.filteredReceiveEventArgs); + this.lifecycleService.InvokeListenersSafely(AgentEvent.PostReceiveEventWithResult, this.filteredReceiveEventArgs); } catch (Exception e) { - Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentFilteredReceiveEvent."); + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAgentReceiveEventWithResult."); } return result; diff --git a/Dalamud/Game/Gui/Dtr/DtrBar.cs b/Dalamud/Game/Gui/Dtr/DtrBar.cs index 5663d0748..e5de6b2bd 100644 --- a/Dalamud/Game/Gui/Dtr/DtrBar.cs +++ b/Dalamud/Game/Gui/Dtr/DtrBar.cs @@ -397,7 +397,15 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar ushort w = 0, h = 0; node->GetTextDrawSize(&w, &h, node->NodeText.StringPtr); - node->SetWidth(w); + + if (data.MinimumWidth > 0) + { + node->SetWidth(Math.Max(data.MinimumWidth, w)); + } + else + { + node->SetWidth(w); + } } var elementWidth = data.TextNode->Width + this.configuration.DtrSpacing; diff --git a/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs b/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs index e0bd8fd49..47e86fde1 100644 --- a/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs +++ b/Dalamud/Game/Gui/Dtr/DtrBarEntry.cs @@ -40,6 +40,11 @@ public interface IReadOnlyDtrBarEntry /// public bool Shown { get; } + /// + /// Gets a value indicating this entry's minimum width. + /// + public ushort MinimumWidth { get; } + /// /// Gets a value indicating whether the user has hidden this entry from view through the Dalamud settings. /// @@ -76,6 +81,11 @@ public interface IDtrBarEntry : IReadOnlyDtrBarEntry /// public new bool Shown { get; set; } + /// + /// Gets or sets a value specifying the requested minimum width to make this entry. + /// + public new ushort MinimumWidth { get; set; } + /// /// Gets or sets an action to be invoked when the user clicks on the dtr entry. /// @@ -128,6 +138,25 @@ internal sealed unsafe class DtrBarEntry : IDisposable, IDtrBarEntry /// public SeString? Tooltip { get; set; } + /// + public ushort MinimumWidth + { + get; + set + { + field = value; + if (this.TextNode is not null) + { + if (this.TextNode->GetWidth() < value) + { + this.TextNode->SetWidth(value); + } + } + + this.Dirty = true; + } + } + /// public Action? OnClick { get; set; } From 470267a18590157633022ec100b1cfd41cf5cd6c Mon Sep 17 00:00:00 2001 From: goaaats Date: Tue, 27 Jan 2026 23:17:22 +0100 Subject: [PATCH 69/99] Restore NetworkMessageDirection enum Fixes API breakage --- .../Game/Network/NetworkMessageDirection.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Dalamud/Game/Network/NetworkMessageDirection.cs diff --git a/Dalamud/Game/Network/NetworkMessageDirection.cs b/Dalamud/Game/Network/NetworkMessageDirection.cs new file mode 100644 index 000000000..12cfc3d17 --- /dev/null +++ b/Dalamud/Game/Network/NetworkMessageDirection.cs @@ -0,0 +1,18 @@ +namespace Dalamud.Game.Network; + +/// +/// This represents the direction of a network message. +/// +[Obsolete("No longer part of public API", true)] +public enum NetworkMessageDirection +{ + /// + /// A zone down message. + /// + ZoneDown, + + /// + /// A zone up message. + /// + ZoneUp, +} From 5c250c17254ec89db2aee7ba34afd2925eca3923 Mon Sep 17 00:00:00 2001 From: goaaats Date: Tue, 27 Jan 2026 23:43:51 +0100 Subject: [PATCH 70/99] Make Framework.DelayTicks() deadlock-safe before the game has started --- Dalamud/Game/Framework.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dalamud/Game/Framework.cs b/Dalamud/Game/Framework.cs index 035745684..e40274043 100644 --- a/Dalamud/Game/Framework.cs +++ b/Dalamud/Game/Framework.cs @@ -121,9 +121,9 @@ internal sealed class Framework : IInternalDisposableService, IFramework /// public Task DelayTicks(long numTicks, CancellationToken cancellationToken = default) { - if (this.frameworkDestroy.IsCancellationRequested) + if (this.frameworkDestroy.IsCancellationRequested) // Going away return Task.FromCanceled(this.frameworkDestroy.Token); - if (numTicks <= 0) + if (numTicks <= 0 || this.frameworkThreadTaskScheduler.BoundThread == null) // Nonsense or before first tick return Task.CompletedTask; var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); From 2b51a2a54e20138c9e049b788ffd27b7d0c348be Mon Sep 17 00:00:00 2001 From: goaaats Date: Wed, 28 Jan 2026 00:35:23 +0100 Subject: [PATCH 71/99] build: 14.0.2.0 --- Dalamud/Dalamud.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index a1a08a908..34b546faf 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -6,7 +6,7 @@ XIV Launcher addon framework - 14.0.1.0 + 14.0.2.0 $(DalamudVersion) $(DalamudVersion) $(DalamudVersion) From 934df7da8adbf199eab6ec5dfa7bd182ea97ea9b Mon Sep 17 00:00:00 2001 From: nebel <9887+nebel@users.noreply.github.com> Date: Thu, 29 Jan 2026 00:16:41 +0900 Subject: [PATCH 72/99] Properly lowercase for tags for plugin installer search --- .../Internal/Windows/PluginInstaller/PluginInstallerWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index e32d31181..d132f0d8d 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -3804,7 +3804,7 @@ internal class PluginInstallerWindow : Window, IDisposable if (!manifest.Punchline.IsNullOrEmpty()) scores.Add(matcher.Matches(manifest.Punchline.ToLowerInvariant()) * 100); if (manifest.Tags != null) - scores.Add(matcher.MatchesAny(manifest.Tags.ToArray()) * 100); + scores.Add(matcher.MatchesAny(manifest.Tags.Select(tag => tag.ToLowerInvariant()).ToArray()) * 100); return scores.Max(); } From 73edaadbcad5311c8cc7aa28e88d599a36c3b273 Mon Sep 17 00:00:00 2001 From: pohky <1510568+pohky@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:51:29 +0100 Subject: [PATCH 73/99] Fix null characters in BitmapCodecInfo strings --- Dalamud/Interface/Textures/Internal/BitmapCodecInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Interface/Textures/Internal/BitmapCodecInfo.cs b/Dalamud/Interface/Textures/Internal/BitmapCodecInfo.cs index ec56caadd..7f5ed4fda 100644 --- a/Dalamud/Interface/Textures/Internal/BitmapCodecInfo.cs +++ b/Dalamud/Interface/Textures/Internal/BitmapCodecInfo.cs @@ -50,6 +50,6 @@ internal sealed class BitmapCodecInfo : IBitmapCodecInfo _ = readFuncPtr(codecInfo, 0, null, &cch); var buf = stackalloc char[(int)cch + 1]; Marshal.ThrowExceptionForHR(readFuncPtr(codecInfo, cch + 1, buf, &cch)); - return new(buf, 0, (int)cch); + return new string(buf, 0, (int)cch).Trim('\0'); } } From 252b7eeb9b4d6b3081471b283538c4c1b3203126 Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Fri, 30 Jan 2026 19:21:46 +0100 Subject: [PATCH 74/99] Replace PeHeader with TerraFX --- Dalamud/Hooking/Hook.cs | 30 ++- Dalamud/Hooking/Internal/PeHeader.cs | 390 --------------------------- 2 files changed, 17 insertions(+), 403 deletions(-) delete mode 100644 Dalamud/Hooking/Internal/PeHeader.cs diff --git a/Dalamud/Hooking/Hook.cs b/Dalamud/Hooking/Hook.cs index c54a8f399..265b118bc 100644 --- a/Dalamud/Hooking/Hook.cs +++ b/Dalamud/Hooking/Hook.cs @@ -6,6 +6,8 @@ using Dalamud.Configuration.Internal; using Dalamud.Hooking.Internal; using Dalamud.Hooking.Internal.Verification; +using TerraFX.Interop.Windows; + namespace Dalamud.Hooking; /// @@ -20,6 +22,8 @@ public abstract class Hook : IDalamudHook where T : Delegate private const ulong IMAGE_ORDINAL_FLAG64 = 0x8000000000000000; // ReSharper disable once InconsistentNaming private const uint IMAGE_ORDINAL_FLAG32 = 0x80000000; + // ReSharper disable once InconsistentNaming + private const int IMAGE_DIRECTORY_ENTRY_IMPORT = 1; #pragma warning restore SA1310 private readonly IntPtr address; @@ -124,25 +128,25 @@ public abstract class Hook : IDalamudHook where T : Delegate module ??= Process.GetCurrentProcess().MainModule; if (module == null) throw new InvalidOperationException("Current module is null?"); - var pDos = (PeHeader.IMAGE_DOS_HEADER*)module.BaseAddress; - var pNt = (PeHeader.IMAGE_FILE_HEADER*)(module.BaseAddress + (int)pDos->e_lfanew + 4); - var isPe64 = pNt->SizeOfOptionalHeader == Marshal.SizeOf(); - PeHeader.IMAGE_DATA_DIRECTORY* pDataDirectory; + var pDos = (IMAGE_DOS_HEADER*)module.BaseAddress; + var pNt = (IMAGE_FILE_HEADER*)(module.BaseAddress + pDos->e_lfanew + 4); + var isPe64 = pNt->SizeOfOptionalHeader == Marshal.SizeOf(); + IMAGE_DATA_DIRECTORY* pDataDirectory; if (isPe64) { - var pOpt = (PeHeader.IMAGE_OPTIONAL_HEADER64*)(module.BaseAddress + (int)pDos->e_lfanew + 4 + Marshal.SizeOf()); - pDataDirectory = &pOpt->ImportTable; + var pOpt = (IMAGE_OPTIONAL_HEADER64*)(module.BaseAddress + pDos->e_lfanew + 4 + Marshal.SizeOf()); + pDataDirectory = &pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; } else { - var pOpt = (PeHeader.IMAGE_OPTIONAL_HEADER32*)(module.BaseAddress + (int)pDos->e_lfanew + 4 + Marshal.SizeOf()); - pDataDirectory = &pOpt->ImportTable; + var pOpt = (IMAGE_OPTIONAL_HEADER32*)(module.BaseAddress + pDos->e_lfanew + 4 + Marshal.SizeOf()); + pDataDirectory = &pOpt->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; } var moduleNameLowerWithNullTerminator = (moduleName + "\0").ToLowerInvariant(); - foreach (ref var importDescriptor in new Span( - (PeHeader.IMAGE_IMPORT_DESCRIPTOR*)(module.BaseAddress + (int)pDataDirectory->VirtualAddress), - (int)(pDataDirectory->Size / Marshal.SizeOf()))) + foreach (ref var importDescriptor in new Span( + (IMAGE_IMPORT_DESCRIPTOR*)(module.BaseAddress + (int)pDataDirectory->VirtualAddress), + (int)(pDataDirectory->Size / Marshal.SizeOf()))) { // Having all zero values signals the end of the table. We didn't find anything. if (importDescriptor.Characteristics == 0) @@ -248,7 +252,7 @@ public abstract class Hook : IDalamudHook where T : Delegate ObjectDisposedException.ThrowIf(this.IsDisposed, this); } - private static unsafe IntPtr FromImportHelper32(IntPtr baseAddress, ref PeHeader.IMAGE_IMPORT_DESCRIPTOR desc, ref PeHeader.IMAGE_DATA_DIRECTORY dir, string functionName, uint hintOrOrdinal) + private static unsafe IntPtr FromImportHelper32(IntPtr baseAddress, ref IMAGE_IMPORT_DESCRIPTOR desc, ref IMAGE_DATA_DIRECTORY dir, string functionName, uint hintOrOrdinal) { var importLookupsOversizedSpan = new Span((uint*)(baseAddress + (int)desc.OriginalFirstThunk), (int)((dir.Size - desc.OriginalFirstThunk) / Marshal.SizeOf())); var importAddressesOversizedSpan = new Span((uint*)(baseAddress + (int)desc.FirstThunk), (int)((dir.Size - desc.FirstThunk) / Marshal.SizeOf())); @@ -298,7 +302,7 @@ public abstract class Hook : IDalamudHook where T : Delegate throw new MissingMethodException("Specified method not found"); } - private static unsafe IntPtr FromImportHelper64(IntPtr baseAddress, ref PeHeader.IMAGE_IMPORT_DESCRIPTOR desc, ref PeHeader.IMAGE_DATA_DIRECTORY dir, string functionName, uint hintOrOrdinal) + private static unsafe IntPtr FromImportHelper64(IntPtr baseAddress, ref IMAGE_IMPORT_DESCRIPTOR desc, ref IMAGE_DATA_DIRECTORY dir, string functionName, uint hintOrOrdinal) { var importLookupsOversizedSpan = new Span((ulong*)(baseAddress + (int)desc.OriginalFirstThunk), (int)((dir.Size - desc.OriginalFirstThunk) / Marshal.SizeOf())); var importAddressesOversizedSpan = new Span((ulong*)(baseAddress + (int)desc.FirstThunk), (int)((dir.Size - desc.FirstThunk) / Marshal.SizeOf())); diff --git a/Dalamud/Hooking/Internal/PeHeader.cs b/Dalamud/Hooking/Internal/PeHeader.cs deleted file mode 100644 index 51df4a174..000000000 --- a/Dalamud/Hooking/Internal/PeHeader.cs +++ /dev/null @@ -1,390 +0,0 @@ -using System.Runtime.InteropServices; - -#pragma warning disable -namespace Dalamud.Hooking.Internal; - -internal class PeHeader -{ - public struct IMAGE_DOS_HEADER - { - public UInt16 e_magic; - public UInt16 e_cblp; - public UInt16 e_cp; - public UInt16 e_crlc; - public UInt16 e_cparhdr; - public UInt16 e_minalloc; - public UInt16 e_maxalloc; - public UInt16 e_ss; - public UInt16 e_sp; - public UInt16 e_csum; - public UInt16 e_ip; - public UInt16 e_cs; - public UInt16 e_lfarlc; - public UInt16 e_ovno; - public UInt16 e_res_0; - public UInt16 e_res_1; - public UInt16 e_res_2; - public UInt16 e_res_3; - public UInt16 e_oemid; - public UInt16 e_oeminfo; - public UInt16 e_res2_0; - public UInt16 e_res2_1; - public UInt16 e_res2_2; - public UInt16 e_res2_3; - public UInt16 e_res2_4; - public UInt16 e_res2_5; - public UInt16 e_res2_6; - public UInt16 e_res2_7; - public UInt16 e_res2_8; - public UInt16 e_res2_9; - public UInt32 e_lfanew; - } - - [StructLayout(LayoutKind.Sequential)] - public struct IMAGE_DATA_DIRECTORY - { - public UInt32 VirtualAddress; - public UInt32 Size; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct IMAGE_OPTIONAL_HEADER32 - { - public UInt16 Magic; - public Byte MajorLinkerVersion; - public Byte MinorLinkerVersion; - public UInt32 SizeOfCode; - public UInt32 SizeOfInitializedData; - public UInt32 SizeOfUninitializedData; - public UInt32 AddressOfEntryPoint; - public UInt32 BaseOfCode; - public UInt32 BaseOfData; - public UInt32 ImageBase; - public UInt32 SectionAlignment; - public UInt32 FileAlignment; - public UInt16 MajorOperatingSystemVersion; - public UInt16 MinorOperatingSystemVersion; - public UInt16 MajorImageVersion; - public UInt16 MinorImageVersion; - public UInt16 MajorSubsystemVersion; - public UInt16 MinorSubsystemVersion; - public UInt32 Win32VersionValue; - public UInt32 SizeOfImage; - public UInt32 SizeOfHeaders; - public UInt32 CheckSum; - public UInt16 Subsystem; - public UInt16 DllCharacteristics; - public UInt32 SizeOfStackReserve; - public UInt32 SizeOfStackCommit; - public UInt32 SizeOfHeapReserve; - public UInt32 SizeOfHeapCommit; - public UInt32 LoaderFlags; - public UInt32 NumberOfRvaAndSizes; - - public IMAGE_DATA_DIRECTORY ExportTable; - public IMAGE_DATA_DIRECTORY ImportTable; - public IMAGE_DATA_DIRECTORY ResourceTable; - public IMAGE_DATA_DIRECTORY ExceptionTable; - public IMAGE_DATA_DIRECTORY CertificateTable; - public IMAGE_DATA_DIRECTORY BaseRelocationTable; - public IMAGE_DATA_DIRECTORY Debug; - public IMAGE_DATA_DIRECTORY Architecture; - public IMAGE_DATA_DIRECTORY GlobalPtr; - public IMAGE_DATA_DIRECTORY TLSTable; - public IMAGE_DATA_DIRECTORY LoadConfigTable; - public IMAGE_DATA_DIRECTORY BoundImport; - public IMAGE_DATA_DIRECTORY IAT; - public IMAGE_DATA_DIRECTORY DelayImportDescriptor; - public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; - public IMAGE_DATA_DIRECTORY Reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct IMAGE_OPTIONAL_HEADER64 - { - public UInt16 Magic; - public Byte MajorLinkerVersion; - public Byte MinorLinkerVersion; - public UInt32 SizeOfCode; - public UInt32 SizeOfInitializedData; - public UInt32 SizeOfUninitializedData; - public UInt32 AddressOfEntryPoint; - public UInt32 BaseOfCode; - public UInt64 ImageBase; - public UInt32 SectionAlignment; - public UInt32 FileAlignment; - public UInt16 MajorOperatingSystemVersion; - public UInt16 MinorOperatingSystemVersion; - public UInt16 MajorImageVersion; - public UInt16 MinorImageVersion; - public UInt16 MajorSubsystemVersion; - public UInt16 MinorSubsystemVersion; - public UInt32 Win32VersionValue; - public UInt32 SizeOfImage; - public UInt32 SizeOfHeaders; - public UInt32 CheckSum; - public UInt16 Subsystem; - public UInt16 DllCharacteristics; - public UInt64 SizeOfStackReserve; - public UInt64 SizeOfStackCommit; - public UInt64 SizeOfHeapReserve; - public UInt64 SizeOfHeapCommit; - public UInt32 LoaderFlags; - public UInt32 NumberOfRvaAndSizes; - - public IMAGE_DATA_DIRECTORY ExportTable; - public IMAGE_DATA_DIRECTORY ImportTable; - public IMAGE_DATA_DIRECTORY ResourceTable; - public IMAGE_DATA_DIRECTORY ExceptionTable; - public IMAGE_DATA_DIRECTORY CertificateTable; - public IMAGE_DATA_DIRECTORY BaseRelocationTable; - public IMAGE_DATA_DIRECTORY Debug; - public IMAGE_DATA_DIRECTORY Architecture; - public IMAGE_DATA_DIRECTORY GlobalPtr; - public IMAGE_DATA_DIRECTORY TLSTable; - public IMAGE_DATA_DIRECTORY LoadConfigTable; - public IMAGE_DATA_DIRECTORY BoundImport; - public IMAGE_DATA_DIRECTORY IAT; - public IMAGE_DATA_DIRECTORY DelayImportDescriptor; - public IMAGE_DATA_DIRECTORY CLRRuntimeHeader; - public IMAGE_DATA_DIRECTORY Reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct IMAGE_FILE_HEADER - { - public UInt16 Machine; - public UInt16 NumberOfSections; - public UInt32 TimeDateStamp; - public UInt32 PointerToSymbolTable; - public UInt32 NumberOfSymbols; - public UInt16 SizeOfOptionalHeader; - public UInt16 Characteristics; - } - - [StructLayout(LayoutKind.Explicit)] - public struct IMAGE_SECTION_HEADER - { - [FieldOffset(0)] - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public char[] Name; - [FieldOffset(8)] - public UInt32 VirtualSize; - [FieldOffset(12)] - public UInt32 VirtualAddress; - [FieldOffset(16)] - public UInt32 SizeOfRawData; - [FieldOffset(20)] - public UInt32 PointerToRawData; - [FieldOffset(24)] - public UInt32 PointerToRelocations; - [FieldOffset(28)] - public UInt32 PointerToLinenumbers; - [FieldOffset(32)] - public UInt16 NumberOfRelocations; - [FieldOffset(34)] - public UInt16 NumberOfLinenumbers; - [FieldOffset(36)] - public DataSectionFlags Characteristics; - - public string Section - { - get { return new string(Name); } - } - } - - [Flags] - public enum DataSectionFlags : uint - { - /// - /// Reserved for future use. - /// - TypeReg = 0x00000000, - /// - /// Reserved for future use. - /// - TypeDsect = 0x00000001, - /// - /// Reserved for future use. - /// - TypeNoLoad = 0x00000002, - /// - /// Reserved for future use. - /// - TypeGroup = 0x00000004, - /// - /// The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. - /// - TypeNoPadded = 0x00000008, - /// - /// Reserved for future use. - /// - TypeCopy = 0x00000010, - /// - /// The section contains executable code. - /// - ContentCode = 0x00000020, - /// - /// The section contains initialized data. - /// - ContentInitializedData = 0x00000040, - /// - /// The section contains uninitialized data. - /// - ContentUninitializedData = 0x00000080, - /// - /// Reserved for future use. - /// - LinkOther = 0x00000100, - /// - /// The section contains comments or other information. The .drectve section has this type. This is valid for object files only. - /// - LinkInfo = 0x00000200, - /// - /// Reserved for future use. - /// - TypeOver = 0x00000400, - /// - /// The section will not become part of the image. This is valid only for object files. - /// - LinkRemove = 0x00000800, - /// - /// The section contains COMDAT data. For more information, see section 5.5.6, COMDAT Sections (Object Only). This is valid only for object files. - /// - LinkComDat = 0x00001000, - /// - /// Reset speculative exceptions handling bits in the TLB entries for this section. - /// - NoDeferSpecExceptions = 0x00004000, - /// - /// The section contains data referenced through the global pointer (GP). - /// - RelativeGP = 0x00008000, - /// - /// Reserved for future use. - /// - MemPurgeable = 0x00020000, - /// - /// Reserved for future use. - /// - Memory16Bit = 0x00020000, - /// - /// Reserved for future use. - /// - MemoryLocked = 0x00040000, - /// - /// Reserved for future use. - /// - MemoryPreload = 0x00080000, - /// - /// Align data on a 1-byte boundary. Valid only for object files. - /// - Align1Bytes = 0x00100000, - /// - /// Align data on a 2-byte boundary. Valid only for object files. - /// - Align2Bytes = 0x00200000, - /// - /// Align data on a 4-byte boundary. Valid only for object files. - /// - Align4Bytes = 0x00300000, - /// - /// Align data on an 8-byte boundary. Valid only for object files. - /// - Align8Bytes = 0x00400000, - /// - /// Align data on a 16-byte boundary. Valid only for object files. - /// - Align16Bytes = 0x00500000, - /// - /// Align data on a 32-byte boundary. Valid only for object files. - /// - Align32Bytes = 0x00600000, - /// - /// Align data on a 64-byte boundary. Valid only for object files. - /// - Align64Bytes = 0x00700000, - /// - /// Align data on a 128-byte boundary. Valid only for object files. - /// - Align128Bytes = 0x00800000, - /// - /// Align data on a 256-byte boundary. Valid only for object files. - /// - Align256Bytes = 0x00900000, - /// - /// Align data on a 512-byte boundary. Valid only for object files. - /// - Align512Bytes = 0x00A00000, - /// - /// Align data on a 1024-byte boundary. Valid only for object files. - /// - Align1024Bytes = 0x00B00000, - /// - /// Align data on a 2048-byte boundary. Valid only for object files. - /// - Align2048Bytes = 0x00C00000, - /// - /// Align data on a 4096-byte boundary. Valid only for object files. - /// - Align4096Bytes = 0x00D00000, - /// - /// Align data on an 8192-byte boundary. Valid only for object files. - /// - Align8192Bytes = 0x00E00000, - /// - /// The section contains extended relocations. - /// - LinkExtendedRelocationOverflow = 0x01000000, - /// - /// The section can be discarded as needed. - /// - MemoryDiscardable = 0x02000000, - /// - /// The section cannot be cached. - /// - MemoryNotCached = 0x04000000, - /// - /// The section is not pageable. - /// - MemoryNotPaged = 0x08000000, - /// - /// The section can be shared in memory. - /// - MemoryShared = 0x10000000, - /// - /// The section can be executed as code. - /// - MemoryExecute = 0x20000000, - /// - /// The section can be read. - /// - MemoryRead = 0x40000000, - /// - /// The section can be written to. - /// - MemoryWrite = 0x80000000 - } - - [StructLayout(LayoutKind.Explicit)] - public struct IMAGE_IMPORT_DESCRIPTOR - { - [FieldOffset(0)] - public uint Characteristics; - - [FieldOffset(0)] - public uint OriginalFirstThunk; - - [FieldOffset(4)] - public uint TimeDateStamp; - - [FieldOffset(8)] - public uint ForwarderChain; - - [FieldOffset(12)] - public uint Name; - - [FieldOffset(16)] - public uint FirstThunk; - } -} From aa4ace976e12e3dcbdd0f9f424900b27047a690d Mon Sep 17 00:00:00 2001 From: bleatbot <106497096+bleatbot@users.noreply.github.com> Date: Sat, 31 Jan 2026 21:56:36 +0100 Subject: [PATCH 75/99] Update ClientStructs (#2598) Co-authored-by: github-actions[bot] --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index a02536a4b..cb1f076a6 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit a02536a4bf6862036403c03945a02fcd6689e445 +Subproject commit cb1f076a6fcb6131cd8e1d5bda438adc980b3ee3 From 33a7cdefa8b47ef0ec7d25f62971aed613979ca1 Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Sat, 31 Jan 2026 21:57:11 +0100 Subject: [PATCH 76/99] Switch to CS in NetworkMonitorWidget (#2600) * Switch to CS in NetworkMonitorWidget * Lazy-init the hooks * Fix warnings --- Dalamud/Game/Gui/ContextMenu/ContextMenu.cs | 2 +- .../Windows/Data/Widgets/GaugeWidget.cs | 2 +- .../Windows/Data/Widgets/HookWidget.cs | 2 +- .../Data/Widgets/NetworkMonitorWidget.cs | 28 ++++++++----------- Dalamud/Plugin/Services/ITextureProvider.cs | 4 +-- 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs b/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs index 0b306f093..ab3da7bf3 100644 --- a/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs +++ b/Dalamud/Game/Gui/ContextMenu/ContextMenu.cs @@ -336,7 +336,7 @@ internal sealed unsafe class ContextMenu : IInternalDisposableService, IContextM this.MenuCallbackIds.Clear(); this.SelectedAgent = agent; var unitManager = RaptureAtkUnitManager.Instance(); - this.SelectedParentAddon = unitManager->GetAddonById(unitManager->GetAddonByName(addonName)->ContextMenuParentId); + this.SelectedParentAddon = unitManager->GetAddonById(unitManager->GetAddonByName(addonName)->BlockedParentId); this.SelectedEventInterfaces.Clear(); if (this.SelectedAgent == AgentInventoryContext.Instance()) { diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs index 74403a32b..8badcfaf8 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GaugeWidget.cs @@ -62,7 +62,7 @@ internal class GaugeWidget : IDataWindowWidget 40 => jobGauges.Get(), 41 => jobGauges.Get(), 42 => jobGauges.Get(), - _ => null + _ => null, }; if (gauge == null) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs index fd27996ed..e19281b40 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/HookWidget.cs @@ -50,7 +50,7 @@ internal unsafe class HookWidget : IDataWindowWidget { MessageBoxW, AddonFinalize, - Random + Random, } /// diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs index 922b72717..4460a9f9a 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs @@ -2,7 +2,6 @@ using System.Collections.Concurrent; using System.Threading; using Dalamud.Bindings.ImGui; -using Dalamud.Game; using Dalamud.Hooking; using Dalamud.Interface.Components; using Dalamud.Interface.Utility.Raii; @@ -23,7 +22,7 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget private readonly ConcurrentQueue packets = new(); private Hook? hookDown; - private Hook? hookUp; + private Hook? hookUp; private bool trackNetwork; private int trackedPackets = 20; @@ -40,8 +39,6 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget this.hookUp?.Dispose(); } - private delegate byte ZoneClientSendPacketDelegate(ZoneClient* thisPtr, nint packet, uint a3, uint a4, byte a5); - private enum NetworkMessageDirection { ZoneDown, @@ -58,22 +55,19 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget public bool Ready { get; set; } /// - public void Load() - { - this.hookDown = Hook.FromAddress( - (nint)PacketDispatcher.StaticVirtualTablePointer->OnReceivePacket, - this.OnReceivePacketDetour); - - // TODO: switch to ZoneClient.SendPacket from CS - if (Service.Get().TryScanText("E8 ?? ?? ?? ?? 4C 8B 44 24 ?? E9", out var address)) - this.hookUp = Hook.FromAddress(address, this.SendPacketDetour); - - this.Ready = true; - } + public void Load() => this.Ready = true; /// public void Draw() { + this.hookDown ??= Hook.FromAddress( + (nint)PacketDispatcher.StaticVirtualTablePointer->OnReceivePacket, + this.OnReceivePacketDetour); + + this.hookUp ??= Hook.FromAddress( + (nint)ZoneClient.MemberFunctionPointers.SendPacket, + this.SendPacketDetour); + if (ImGui.Checkbox("Track Network Packets"u8, ref this.trackNetwork)) { if (this.trackNetwork) @@ -213,7 +207,7 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget this.hookDown.OriginalDisposeSafe(thisPtr, targetId, packet); } - private byte SendPacketDetour(ZoneClient* thisPtr, nint packet, uint a3, uint a4, byte a5) + private bool SendPacketDetour(ZoneClient* thisPtr, nint packet, uint a3, uint a4, bool a5) { var opCode = *(ushort*)packet; this.RecordPacket(new NetworkPacketData(Interlocked.Increment(ref this.nextPacketIndex), DateTime.Now, opCode, NetworkMessageDirection.ZoneUp, 0, string.Empty)); diff --git a/Dalamud/Plugin/Services/ITextureProvider.cs b/Dalamud/Plugin/Services/ITextureProvider.cs index a4d1dcbd2..63a463613 100644 --- a/Dalamud/Plugin/Services/ITextureProvider.cs +++ b/Dalamud/Plugin/Services/ITextureProvider.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; @@ -322,7 +322,7 @@ public interface ITextureProvider : IDalamudService /// Whether to leave non-disposed when the returned /// completes. /// Address of the new . - /// See PrintTextureInfo in for an example + /// See PrintTextureInfo in for an example /// of replacing the texture of an image node. /// /// If the returned kernel texture is to be destroyed, call the fourth function in its vtable, by calling From d8a13a72aa941bb41ff52020f1a848e197d4a65a Mon Sep 17 00:00:00 2001 From: Infi Date: Thu, 5 Feb 2026 00:20:39 +0100 Subject: [PATCH 77/99] - Add the CustomizeData struct to ICharacter - API 15 note the Customize array --- .../ClientState/Customize/CustomizeData.cs | 314 ++++++++++++++++++ .../ClientState/Objects/Types/Character.cs | 49 +-- 2 files changed, 344 insertions(+), 19 deletions(-) create mode 100644 Dalamud/Game/ClientState/Customize/CustomizeData.cs diff --git a/Dalamud/Game/ClientState/Customize/CustomizeData.cs b/Dalamud/Game/ClientState/Customize/CustomizeData.cs new file mode 100644 index 000000000..644bec5e8 --- /dev/null +++ b/Dalamud/Game/ClientState/Customize/CustomizeData.cs @@ -0,0 +1,314 @@ +using Dalamud.Game.ClientState.Objects.Types; + +namespace Dalamud.Game.ClientState.Customize; + +/// +/// This collection represents customization data a has. +/// +public interface ICustomizeData +{ + /// + /// Gets the current race. + /// E.g., Miqo'te, Aura + /// + public byte Race { get; } + + /// + /// Gets the current sex. + /// + public byte Sex { get; } + + /// + /// Gets the current body type. + /// + public byte BodyType { get; } + + /// + /// Gets the current height. + /// 0 to 100 + /// + public byte Height { get; } + + /// + /// Gets the current tribe. + /// E.g., Seeker of the Sun, Keeper of the Moon + /// + public byte Tribe { get; } + + /// + /// Gets the current face. + /// 1 to 4 + /// + public byte Face { get; } + + /// + /// Gets the current hairstyle. + /// + public byte Hairstyle { get; } + + /// + /// Gets the current skin color. + /// + public byte SkinColor { get; } + + /// + /// Gets the current color of the left eye. + /// + public byte EyeColorLeft { get; } + + /// + /// Gets the current color of the right eye. + /// + public byte EyeColorRight { get; } + + /// + /// Gets the current main hair color. + /// + public byte HairColor { get; } + + /// + /// Gets the current highlight hair color. + /// + public byte HighlightsColor { get; } + + /// + /// Gets the current tattoo color. + /// + public byte TattooColor { get; } + + /// + /// Gets the current eyebrow type. + /// + public byte Eyebrows { get; } + + /// + /// Gets the current nose type. + /// + public byte Nose { get; } + + /// + /// Gets the current jaw type. + /// + public byte Jaw { get; } + + /// + /// Gets the current lip color fur pattern. + /// + public byte LipColorFurPattern { get; } + + /// + /// Gets the current muscle mass value. + /// + public byte MuscleMass { get; } + + /// + /// Gets the current tail type. + /// + public byte TailShape { get; } + + /// + /// Gets the current bust size. + /// 0 to 100 + /// + public byte BustSize { get; } + + /// + /// Gets the current color of the face paint. + /// + public byte FacePaintColor { get; } + + /// + /// Gets a value indicating whether highlight color is used. + /// + public bool Highlights { get; } + + /// + /// Gets a value indicating whether this facial feature is used. + /// + public bool FacialFeature1 { get; } + + /// + public bool FacialFeature2 { get; } + + /// + public bool FacialFeature3 { get; } + + /// + public bool FacialFeature4 { get; } + + /// + public bool FacialFeature5 { get; } + + /// + public bool FacialFeature6 { get; } + + /// + public bool FacialFeature7 { get; } + + /// + /// Gets a value indicating whether the legacy tattoo is used. + /// + public bool LegacyTattoo { get; } + + /// + /// Gets the current eye shape type. + /// + public byte EyeShape { get; } + + /// + /// Gets a value indicating whether small iris is used. + /// + public bool SmallIris { get; } + + /// + /// Gets the current mouth type. + /// + public byte Mouth { get; } + + /// + /// Gets a value indicating whether lipstick is used. + /// + public bool Lipstick { get; } + + /// + /// Gets the current face paint type. + /// + public byte FacePaint { get; } + + /// + /// Gets a value indicating whether face paint reversed is used. + /// + public bool FacePaintReversed { get; } +} + +/// +internal readonly unsafe struct CustomizeData : ICustomizeData +{ + /// + /// Gets or sets the address of the customize data struct in memory. + /// + public readonly nint Address; + + /// + /// Initializes a new instance of the struct. + /// + /// Address of the status list. + internal CustomizeData(nint address) + { + this.Address = address; + } + + /// + public byte Race => this.Struct->Race; + + /// + public byte Sex => this.Struct->Sex; + + /// + public byte BodyType => this.Struct->BodyType; + + /// + public byte Height => this.Struct->Height; + + /// + public byte Tribe => this.Struct->Tribe; + + /// + public byte Face => this.Struct->Face; + + /// + public byte Hairstyle => this.Struct->Hairstyle; + + /// + public byte SkinColor => this.Struct->SkinColor; + + /// + public byte EyeColorLeft => this.Struct->EyeColorLeft; + + /// + public byte EyeColorRight => this.Struct->EyeColorRight; + + /// + public byte HairColor => this.Struct->HairColor; + + /// + public byte HighlightsColor => this.Struct->HighlightsColor; + + /// + public byte TattooColor => this.Struct->TattooColor; + + /// + public byte Eyebrows => this.Struct->Eyebrows; + + /// + public byte Nose => this.Struct->Nose; + + /// + public byte Jaw => this.Struct->Jaw; + + /// + public byte LipColorFurPattern => this.Struct->LipColorFurPattern; + + /// + public byte MuscleMass => this.Struct->MuscleMass; + + /// + public byte TailShape => this.Struct->TailShape; + + /// + public byte BustSize => this.Struct->BustSize; + + /// + public byte FacePaintColor => this.Struct->FacePaintColor; + + /// + public bool Highlights => this.Struct->Highlights; + + /// + public bool FacialFeature1 => this.Struct->FacialFeature1; + + /// + public bool FacialFeature2 => this.Struct->FacialFeature2; + + /// + public bool FacialFeature3 => this.Struct->FacialFeature3; + + /// + public bool FacialFeature4 => this.Struct->FacialFeature4; + + /// + public bool FacialFeature5 => this.Struct->FacialFeature5; + + /// + public bool FacialFeature6 => this.Struct->FacialFeature6; + + /// + public bool FacialFeature7 => this.Struct->FacialFeature7; + + /// + public bool LegacyTattoo => this.Struct->LegacyTattoo; + + /// + public byte EyeShape => this.Struct->EyeShape; + + /// + public bool SmallIris => this.Struct->SmallIris; + + /// + public byte Mouth => this.Struct->Mouth; + + /// + public bool Lipstick => this.Struct->Lipstick; + + /// + public byte FacePaint => this.Struct->FacePaint; + + /// + public bool FacePaintReversed => this.Struct->FacePaintReversed; + + /// + /// Gets the underlying structure. + /// + internal FFXIVClientStructs.FFXIV.Client.Game.Character.CustomizeData* Struct => + (FFXIVClientStructs.FFXIV.Client.Game.Character.CustomizeData*)this.Address; +} diff --git a/Dalamud/Game/ClientState/Objects/Types/Character.cs b/Dalamud/Game/ClientState/Objects/Types/Character.cs index 2002a16b8..f122f1f27 100644 --- a/Dalamud/Game/ClientState/Objects/Types/Character.cs +++ b/Dalamud/Game/ClientState/Objects/Types/Character.cs @@ -1,6 +1,8 @@ using Dalamud.Data; +using Dalamud.Game.ClientState.Customize; using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.Text.SeStringHandling; +using Dalamud.Utility; using Lumina.Excel; using Lumina.Excel.Sheets; @@ -13,68 +15,73 @@ namespace Dalamud.Game.ClientState.Objects.Types; public interface ICharacter : IGameObject { /// - /// Gets the current HP of this Chara. + /// Gets the current HP of this character. /// public uint CurrentHp { get; } /// - /// Gets the maximum HP of this Chara. + /// Gets the maximum HP of this character. /// public uint MaxHp { get; } /// - /// Gets the current MP of this Chara. + /// Gets the current MP of this character. /// public uint CurrentMp { get; } /// - /// Gets the maximum MP of this Chara. + /// Gets the maximum MP of this character. /// public uint MaxMp { get; } /// - /// Gets the current GP of this Chara. + /// Gets the current GP of this character. /// public uint CurrentGp { get; } /// - /// Gets the maximum GP of this Chara. + /// Gets the maximum GP of this character. /// public uint MaxGp { get; } /// - /// Gets the current CP of this Chara. + /// Gets the current CP of this character. /// public uint CurrentCp { get; } /// - /// Gets the maximum CP of this Chara. + /// Gets the maximum CP of this character. /// public uint MaxCp { get; } /// - /// Gets the shield percentage of this Chara. + /// Gets the shield percentage of this character. /// public byte ShieldPercentage { get; } /// - /// Gets the ClassJob of this Chara. + /// Gets the ClassJob of this character. /// public RowRef ClassJob { get; } /// - /// Gets the level of this Chara. + /// Gets the level of this character. /// public byte Level { get; } /// - /// Gets a byte array describing the visual appearance of this Chara. + /// Gets a byte array describing the visual appearance of this character. /// Indexed by . /// public byte[] Customize { get; } /// - /// Gets the Free Company tag of this chara. + /// Gets the underlying CustomizeData struct for this character. + /// + public ICustomizeData CustomizeData { get; } + + /// + /// Gets the Free Company tag of this character. /// public SeString CompanyTag { get; } @@ -92,12 +99,12 @@ public interface ICharacter : IGameObject /// Gets the status flags. /// public StatusFlags StatusFlags { get; } - + /// /// Gets the current mount for this character. Will be null if the character doesn't have a mount. /// public RowRef? CurrentMount { get; } - + /// /// Gets the current minion summoned for this character. Will be null if the character doesn't have a minion. /// This method *will* return information about a spawned (but invisible) minion, e.g. if the character is riding a @@ -116,7 +123,7 @@ internal unsafe class Character : GameObject, ICharacter /// This represents a non-static entity. /// /// The address of this character in memory. - internal Character(IntPtr address) + internal Character(nint address) : base(address) { } @@ -155,8 +162,12 @@ internal unsafe class Character : GameObject, ICharacter public byte Level => this.Struct->CharacterData.Level; /// + [Api15ToDo("Do not allocate on each call, use the CS Span and let consumers do allocation if necessary")] public byte[] Customize => this.Struct->DrawData.CustomizeData.Data.ToArray(); + /// + public ICustomizeData CustomizeData => new CustomizeData((nint)(&this.Struct->DrawData.CustomizeData)); + /// public SeString CompanyTag => SeString.Parse(this.Struct->FreeCompanyTag); @@ -183,14 +194,14 @@ internal unsafe class Character : GameObject, ICharacter (this.Struct->IsAllianceMember ? StatusFlags.AllianceMember : StatusFlags.None) | (this.Struct->IsFriend ? StatusFlags.Friend : StatusFlags.None) | (this.Struct->IsCasting ? StatusFlags.IsCasting : StatusFlags.None); - + /// public RowRef? CurrentMount { get { if (this.Struct->IsNotMounted()) return null; // just for safety. - + var mountId = this.Struct->Mount.MountId; return mountId == 0 ? null : LuminaUtils.CreateRef(mountId); } @@ -201,7 +212,7 @@ internal unsafe class Character : GameObject, ICharacter { get { - if (this.Struct->CompanionObject != null) + if (this.Struct->CompanionObject != null) return LuminaUtils.CreateRef(this.Struct->CompanionObject->BaseId); // this is only present if a minion is summoned but hidden (e.g. the player's on a mount). From dc77235c969c56c00fd11827ff48de5724c0ddf2 Mon Sep 17 00:00:00 2001 From: Infi Date: Thu, 5 Feb 2026 00:37:12 +0100 Subject: [PATCH 78/99] - Fix style cop warnings --- Dalamud/Game/ClientState/Customize/CustomizeData.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dalamud/Game/ClientState/Customize/CustomizeData.cs b/Dalamud/Game/ClientState/Customize/CustomizeData.cs index 644bec5e8..5e861db65 100644 --- a/Dalamud/Game/ClientState/Customize/CustomizeData.cs +++ b/Dalamud/Game/ClientState/Customize/CustomizeData.cs @@ -9,7 +9,7 @@ public interface ICustomizeData { /// /// Gets the current race. - /// E.g., Miqo'te, Aura + /// E.g., Miqo'te, Aura. /// public byte Race { get; } @@ -31,13 +31,13 @@ public interface ICustomizeData /// /// Gets the current tribe. - /// E.g., Seeker of the Sun, Keeper of the Moon + /// E.g., Seeker of the Sun, Keeper of the Moon. /// public byte Tribe { get; } /// /// Gets the current face. - /// 1 to 4 + /// 1 to 4. /// public byte Face { get; } @@ -108,7 +108,7 @@ public interface ICustomizeData /// /// Gets the current bust size. - /// 0 to 100 + /// 0 to 100. /// public byte BustSize { get; } From bcf4f396d6d1fd58826c42efe2c842027eba383e Mon Sep 17 00:00:00 2001 From: Infi Date: Thu, 5 Feb 2026 01:12:00 +0100 Subject: [PATCH 79/99] - Adjust comments --- Dalamud/Game/ClientState/Customize/CustomizeData.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Dalamud/Game/ClientState/Customize/CustomizeData.cs b/Dalamud/Game/ClientState/Customize/CustomizeData.cs index 5e861db65..baf8d3a0a 100644 --- a/Dalamud/Game/ClientState/Customize/CustomizeData.cs +++ b/Dalamud/Game/ClientState/Customize/CustomizeData.cs @@ -24,8 +24,7 @@ public interface ICustomizeData public byte BodyType { get; } /// - /// Gets the current height. - /// 0 to 100 + /// Gets the current height (0 to 100). /// public byte Height { get; } @@ -36,8 +35,7 @@ public interface ICustomizeData public byte Tribe { get; } /// - /// Gets the current face. - /// 1 to 4. + /// Gets the current face (1 to 4). /// public byte Face { get; } @@ -102,13 +100,12 @@ public interface ICustomizeData public byte MuscleMass { get; } /// - /// Gets the current tail type. + /// Gets the current tail type (1 to 4). /// public byte TailShape { get; } /// - /// Gets the current bust size. - /// 0 to 100. + /// Gets the current bust size (0 to 100). /// public byte BustSize { get; } From d3b9c75e505c33753e32268b98c8000a03f5bfda Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 5 Feb 2026 17:35:21 +0000 Subject: [PATCH 80/99] Update ClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index cb1f076a6..9ba281cab 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit cb1f076a6fcb6131cd8e1d5bda438adc980b3ee3 +Subproject commit 9ba281cab958049b47bbf7199ab14742c609cd4b From 7d2f12c6e2de70806ed6eea776a0c902577d5877 Mon Sep 17 00:00:00 2001 From: goaaats Date: Thu, 5 Feb 2026 19:56:25 +0100 Subject: [PATCH 81/99] build: 14.0.2.1 --- Dalamud/Dalamud.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 34b546faf..adaf876ee 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -6,7 +6,7 @@ XIV Launcher addon framework - 14.0.2.0 + 14.0.2.1 $(DalamudVersion) $(DalamudVersion) $(DalamudVersion) From b30a93816b82a5a2ae16a33a1820f45117adbc87 Mon Sep 17 00:00:00 2001 From: Soreepeong <3614868+Soreepeong@users.noreply.github.com> Date: Fri, 6 Feb 2026 18:59:02 +0900 Subject: [PATCH 82/99] Directly work with TexHeader and TextureBuffer --- .../GamePathSharedImmediateTexture.cs | 2 +- .../Textures/Internal/TextureManager.cs | 37 +++++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/GamePathSharedImmediateTexture.cs b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/GamePathSharedImmediateTexture.cs index 185ae07b9..a320d921e 100644 --- a/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/GamePathSharedImmediateTexture.cs +++ b/Dalamud/Interface/Textures/Internal/SharedImmediateTextures/GamePathSharedImmediateTexture.cs @@ -70,7 +70,7 @@ internal sealed class GamePathSharedImmediateTexture : SharedImmediateTexture } cancellationToken.ThrowIfCancellationRequested(); - var wrap = tm.NoThrottleCreateFromTexFile(file); + var wrap = tm.NoThrottleCreateFromTexFile(file.Header, file.TextureBuffer); tm.BlameSetName(wrap, this.ToString()); return wrap; } diff --git a/Dalamud/Interface/Textures/Internal/TextureManager.cs b/Dalamud/Interface/Textures/Internal/TextureManager.cs index 982b5c58d..22a257395 100644 --- a/Dalamud/Interface/Textures/Internal/TextureManager.cs +++ b/Dalamud/Interface/Textures/Internal/TextureManager.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Dalamud.Configuration.Internal; using Dalamud.Data; using Dalamud.Game; -using Dalamud.Interface.ImGuiSeStringRenderer.Internal; using Dalamud.Interface.Internal; using Dalamud.Interface.Textures.Internal.SharedImmediateTextures; using Dalamud.Interface.Textures.TextureWraps; @@ -20,6 +19,7 @@ using Dalamud.Utility.TerraFxCom; using Lumina.Data; using Lumina.Data.Files; +using Lumina.Data.Parsing.Tex.Buffers; using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; @@ -219,7 +219,7 @@ internal sealed partial class TextureManager null, _ => Task.FromResult( this.BlameSetName( - this.NoThrottleCreateFromTexFile(file), + this.NoThrottleCreateFromTexFile(file.Header, file.TextureBuffer), debugName ?? $"{nameof(this.CreateFromTexFile)}({ForceNullable(file.FilePath)?.Path})")), cancellationToken); @@ -345,14 +345,14 @@ internal sealed partial class TextureManager /// Creates a texture from the given . Skips the load throttler; intended to be used /// from implementation of s. - /// The data. + /// Header of a .tex file. + /// Texture buffer. /// The loaded texture. - internal IDalamudTextureWrap NoThrottleCreateFromTexFile(TexFile file) + internal IDalamudTextureWrap NoThrottleCreateFromTexFile(TexFile.TexHeader header, TextureBuffer buffer) { ObjectDisposedException.ThrowIf(this.disposeCts.IsCancellationRequested, this); - var buffer = file.TextureBuffer; - var (dxgiFormat, conversion) = TexFile.GetDxgiFormatFromTextureFormat(file.Header.Format, false); + var (dxgiFormat, conversion) = TexFile.GetDxgiFormatFromTextureFormat(header.Format, false); if (conversion != TexFile.DxgiFormatConversion.NoConversion || !this.IsDxgiFormatSupported((DXGI_FORMAT)dxgiFormat)) { @@ -361,34 +361,31 @@ internal sealed partial class TextureManager } var wrap = this.NoThrottleCreateFromRaw(new(buffer.Width, buffer.Height, dxgiFormat), buffer.RawData); - this.BlameSetName(wrap, $"{nameof(this.NoThrottleCreateFromTexFile)}({ForceNullable(file.FilePath).Path})"); + this.BlameSetName(wrap, $"{nameof(this.NoThrottleCreateFromTexFile)}({header.Width} x {header.Height})"); return wrap; - - static T? ForceNullable(T s) => s; } /// Creates a texture from the given , trying to interpret it as a /// . /// The file bytes. /// The loaded texture. - internal IDalamudTextureWrap NoThrottleCreateFromTexFile(ReadOnlySpan fileBytes) + internal unsafe IDalamudTextureWrap NoThrottleCreateFromTexFile(ReadOnlySpan fileBytes) { ObjectDisposedException.ThrowIf(this.disposeCts.IsCancellationRequested, this); if (!TexFileExtensions.IsPossiblyTexFile2D(fileBytes)) throw new InvalidDataException("The file is not a TexFile."); - var bytesArray = fileBytes.ToArray(); - var tf = new TexFile(); - typeof(TexFile).GetProperty(nameof(tf.Data))!.GetSetMethod(true)!.Invoke( - tf, - [bytesArray]); - typeof(TexFile).GetProperty(nameof(tf.Reader))!.GetSetMethod(true)!.Invoke( - tf, - [new LuminaBinaryReader(bytesArray)]); - // Note: FileInfo and FilePath are not used from TexFile; skip it. + TexFile.TexHeader header; + TextureBuffer buffer; + fixed (byte* p = fileBytes) + { + var lbr = new LuminaBinaryReader(new UnmanagedMemoryStream(p, fileBytes.Length)); + header = lbr.ReadStructure(); + buffer = TextureBuffer.FromStream(header, lbr); + } - var wrap = this.NoThrottleCreateFromTexFile(tf); + var wrap = this.NoThrottleCreateFromTexFile(header, buffer); this.BlameSetName(wrap, $"{nameof(this.NoThrottleCreateFromTexFile)}({fileBytes.Length:n0})"); return wrap; } From 0490a71990946a34495fbeb6d9f8005e023d4638 Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Sat, 7 Feb 2026 20:36:20 +0100 Subject: [PATCH 83/99] Update Network Monitor Widget - Separate checkboxes for up and down tracking - Clarify tracking is for ZoneUp/ZoneDown - Rephrase filter checkbox tooltip --- .../Data/Widgets/NetworkMonitorWidget.cs | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs index 4460a9f9a..73916761b 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/NetworkMonitorWidget.cs @@ -21,10 +21,11 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget { private readonly ConcurrentQueue packets = new(); - private Hook? hookDown; - private Hook? hookUp; + private Hook? hookZoneDown; + private Hook? hookZoneUp; - private bool trackNetwork; + private bool trackZoneUp; + private bool trackZoneDown; private int trackedPackets = 20; private ulong nextPacketIndex; private string filterString = string.Empty; @@ -35,8 +36,8 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget /// Finalizes an instance of the class. ~NetworkMonitorWidget() { - this.hookDown?.Dispose(); - this.hookUp?.Dispose(); + this.hookZoneDown?.Dispose(); + this.hookZoneUp?.Dispose(); } private enum NetworkMessageDirection @@ -60,26 +61,41 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget /// public void Draw() { - this.hookDown ??= Hook.FromAddress( + this.hookZoneDown ??= Hook.FromAddress( (nint)PacketDispatcher.StaticVirtualTablePointer->OnReceivePacket, this.OnReceivePacketDetour); - this.hookUp ??= Hook.FromAddress( + this.hookZoneUp ??= Hook.FromAddress( (nint)ZoneClient.MemberFunctionPointers.SendPacket, this.SendPacketDetour); - if (ImGui.Checkbox("Track Network Packets"u8, ref this.trackNetwork)) + if (ImGui.Checkbox("Track ZoneUp"u8, ref this.trackZoneUp)) { - if (this.trackNetwork) + if (this.trackZoneUp) { - this.nextPacketIndex = 0; - this.hookDown?.Enable(); - this.hookUp?.Enable(); + if (!this.trackZoneDown) + this.nextPacketIndex = 0; + + this.hookZoneUp?.Enable(); } else { - this.hookDown?.Disable(); - this.hookUp?.Disable(); + this.hookZoneUp?.Disable(); + } + } + + if (ImGui.Checkbox("Track ZoneDown"u8, ref this.trackZoneDown)) + { + if (this.trackZoneDown) + { + if (!this.trackZoneUp) + this.nextPacketIndex = 0; + + this.hookZoneDown?.Enable(); + } + else + { + this.hookZoneDown?.Disable(); } } @@ -92,6 +108,7 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget if (ImGui.Button("Clear Stored Packets"u8)) { this.packets.Clear(); + this.nextPacketIndex = 0; } ImGui.SameLine(); @@ -102,7 +119,7 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); ImGui.Checkbox("##FilterRecording"u8, ref this.filterRecording); if (ImGui.IsItemHovered()) - ImGui.SetTooltip("Apply filter to incoming packets.\nUncheck to record all packets and filter the table instead."u8); + ImGui.SetTooltip("When enabled, packets are filtered before being recorded.\nWhen disabled, all packets are recorded and filtering only affects packets displayed in the table."u8); ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); ImGuiComponents.HelpMarker("Enter OpCodes in a comma-separated list.\nRanges are supported. Exclude OpCodes with exclamation mark.\nExample: -400,!50-100,650,700-980,!941"); @@ -204,14 +221,14 @@ internal unsafe class NetworkMonitorWidget : IDataWindowWidget var opCode = *(ushort*)(packet + 2); var targetName = GetTargetName(targetId); this.RecordPacket(new NetworkPacketData(Interlocked.Increment(ref this.nextPacketIndex), DateTime.Now, opCode, NetworkMessageDirection.ZoneDown, targetId, targetName)); - this.hookDown.OriginalDisposeSafe(thisPtr, targetId, packet); + this.hookZoneDown.OriginalDisposeSafe(thisPtr, targetId, packet); } private bool SendPacketDetour(ZoneClient* thisPtr, nint packet, uint a3, uint a4, bool a5) { var opCode = *(ushort*)packet; this.RecordPacket(new NetworkPacketData(Interlocked.Increment(ref this.nextPacketIndex), DateTime.Now, opCode, NetworkMessageDirection.ZoneUp, 0, string.Empty)); - return this.hookUp.OriginalDisposeSafe(thisPtr, packet, a3, a4, a5); + return this.hookZoneUp.OriginalDisposeSafe(thisPtr, packet, a3, a4, a5); } private void RecordPacket(NetworkPacketData packet) From 73447f205dc5c3a777f3157e9b4085d7a5004bf6 Mon Sep 17 00:00:00 2001 From: Robert Baker Date: Sat, 7 Feb 2026 20:58:55 -0800 Subject: [PATCH 84/99] Add GPU Info to Crash Handler I'm sure there's a better way to do this, but I also shouldn't be allowed to touch any cpp code. This loops through all dxgi adapters based on example code I ripped from Microsoft and StackOverflow and dumps that into the crash log. I'm hoping it doesn't make the window too tall, so if there's a better way to list only the display adapters that are unique, I'm all for it. --- DalamudCrashHandler/DalamudCrashHandler.cpp | 55 +++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/DalamudCrashHandler/DalamudCrashHandler.cpp b/DalamudCrashHandler/DalamudCrashHandler.cpp index f28715dc1..165cce26d 100644 --- a/DalamudCrashHandler/DalamudCrashHandler.cpp +++ b/DalamudCrashHandler/DalamudCrashHandler.cpp @@ -28,6 +28,9 @@ #include #include +#include +#pragma comment(lib, "dxgi.lib") + #pragma comment(lib, "comctl32.lib") #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") @@ -470,6 +473,37 @@ void open_folder_and_select_items(HWND hwndOpener, const std::wstring& path) { ILFree(piid); } +std::vector EnumerateAdapters(void) +{ + IDXGIAdapter1* pAdapter; + std::vector vAdapters; + IDXGIFactory1* pFactory = NULL; + + + // Create a DXGIFactory object. + if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) + { + return vAdapters; + } + + + for (UINT i = 0; + pFactory->EnumAdapters1(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; + ++i) + { + vAdapters.push_back(pAdapter); + } + + + if (pFactory) + { + pFactory->Release(); + } + + return vAdapters; + +} + void export_tspack(HWND hWndParent, const std::filesystem::path& logDir, const std::string& crashLog, const std::string& troubleshootingPackData) { static const char* SourceLogFiles[] = { "output.log", // XIVLauncher for Windows @@ -1022,6 +1056,27 @@ int main() { log << std::format(L"System Time: {0:%F} {0:%T} {0:%Ez}", std::chrono::system_clock::now()) << std::endl; log << std::format(L"CPU Vendor: {}", vendor) << std::endl; log << std::format(L"CPU Brand: {}", brand) << std::endl; + + std::vector availableAdapters = EnumerateAdapters(); + + for (int i = 0; i < availableAdapters.size(); i++) { + auto& myAdapter = *availableAdapters[i]; + auto adapterDescription = DXGI_ADAPTER_DESC1(); + myAdapter.GetDesc1(&adapterDescription); + // Print description to console here + log << std::format(L"GPU Desc: {}", adapterDescription.Description) << std::endl; + } + + /* + for_each(availableAdapters.begin(), availableAdapters.end(), [](IDXGIAdapter1* adapter, , std::wostream log) { + auto& myAdapter = *adapter; + auto adapterDescription = DXGI_ADAPTER_DESC1(); + myAdapter.GetDesc1(&adapterDescription); + // Print description to console here + log << std::format(L"GPU Desc: {}", adapterDescription.Description) << std::endl; + }); + */ + log << L"\n" << stackTrace << std::endl; if (pProgressDialog) From 34f13b3823f4f114742f5eadd04db74418016281 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 8 Feb 2026 06:57:53 +0000 Subject: [PATCH 85/99] Update ClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 9ba281cab..28421f946 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 9ba281cab958049b47bbf7199ab14742c609cd4b +Subproject commit 28421f946ae9ec262630f04b2b4a114b54527ff9 From 78912c155215a05faf5c37252b3f8181ffa389ba Mon Sep 17 00:00:00 2001 From: Glorou Date: Sun, 8 Feb 2026 21:56:48 -0500 Subject: [PATCH 86/99] Init --- Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs | 1 + Dalamud/Interface/ImGuiFileDialog/FileDialog.cs | 2 ++ .../Interface/ImGuiFileDialog/FileDialogManager.cs | 14 ++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs index ef886e957..484b883ee 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs @@ -648,6 +648,7 @@ public partial class FileDialog private void AddFileNameInSelection(string name, bool setLastSelection) { this.selectedFileNames.Add(name); + this.SelectionChanged(this, this.GetFilePathName()); if (this.selectedFileNames.Count == 1) { this.fileNameBuffer = name; diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs index e33fc2fc4..b9ac634ab 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.cs @@ -97,6 +97,8 @@ public partial class FileDialog this.SetupSideBar(); } + public event EventHandler? SelectionChanged; + /// /// Shows the dialog. /// diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs index ee12e7424..eca65cd72 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using Dalamud.Bindings.ImGui; +using FFXIVClientStructs; + namespace Dalamud.Interface.ImGuiFileDialog; /// @@ -25,11 +27,13 @@ public class FileDialogManager #pragma warning restore SA1401 #pragma warning restore SA1201 + public event EventHandler? SelectionChanged; private FileDialog? dialog; private Action? callback; private Action>? multiCallback; private string savedPath = "."; + /// /// Create a dialog which selects an already existing folder. /// @@ -175,6 +179,13 @@ public class FileDialogManager this.multiCallback = null; } + public string? GetCurrentPath() + { + return this.dialog?.GetCurrentPath(); + } + + private void OnSelectionChange(object sender, string path) => this.SelectionChanged(sender, path); + private void SetDialog( string id, string title, @@ -200,9 +211,11 @@ public class FileDialogManager if (this.dialog is not null) { this.dialog.SortOrderChanged -= this.OnSortOrderChange; + this.dialog.SelectionChanged -= this.OnSelectionChange; } this.dialog = new FileDialog(id, title, filters, path, defaultFileName, defaultExtension, selectionCountMax, isModal, flags); + if (this.GetDefaultSortOrder is not null) { try @@ -217,6 +230,7 @@ public class FileDialogManager } this.dialog.SortOrderChanged += this.OnSortOrderChange; + this.dialog.SelectionChanged += this.OnSelectionChange; this.dialog.WindowFlags |= this.AddedWindowFlags; foreach (var (name, location, icon, position) in this.CustomSideBarItems) this.dialog.SetQuickAccess(name, location, icon, position); From 332d0d0cf5bc143401f6a0032d54bb0ea0d7390c Mon Sep 17 00:00:00 2001 From: Glorou Date: Mon, 9 Feb 2026 10:38:14 -0500 Subject: [PATCH 87/99] Tweaked --- Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs | 3 +-- Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs index 484b883ee..289203d59 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs @@ -648,7 +648,6 @@ public partial class FileDialog private void AddFileNameInSelection(string name, bool setLastSelection) { this.selectedFileNames.Add(name); - this.SelectionChanged(this, this.GetFilePathName()); if (this.selectedFileNames.Count == 1) { this.fileNameBuffer = name; @@ -657,7 +656,7 @@ public partial class FileDialog { this.fileNameBuffer = $"{this.selectedFileNames.Count} files Selected"; } - + this.SelectionChanged(this, this.GetFilePathName()); if (setLastSelection) { this.lastSelectedFileName = name; diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs index eca65cd72..5e0a03b66 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs @@ -27,12 +27,13 @@ public class FileDialogManager #pragma warning restore SA1401 #pragma warning restore SA1201 - public event EventHandler? SelectionChanged; + private FileDialog? dialog; private Action? callback; private Action>? multiCallback; private string savedPath = "."; + public event EventHandler? SelectionChanged; /// /// Create a dialog which selects an already existing folder. @@ -184,7 +185,7 @@ public class FileDialogManager return this.dialog?.GetCurrentPath(); } - private void OnSelectionChange(object sender, string path) => this.SelectionChanged(sender, path); + private void OnSelectionChange(object sender, string path) => this.SelectionChanged?.Invoke(sender, path); private void SetDialog( string id, From 256ab9dc9c11d0c73a9449dbf8994ed7a75f89e9 Mon Sep 17 00:00:00 2001 From: Glorou Date: Mon, 9 Feb 2026 10:38:32 -0500 Subject: [PATCH 88/99] add whitespace --- Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs index 289203d59..b1fc6e049 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialog.UI.cs @@ -656,6 +656,7 @@ public partial class FileDialog { this.fileNameBuffer = $"{this.selectedFileNames.Count} files Selected"; } + this.SelectionChanged(this, this.GetFilePathName()); if (setLastSelection) { From 8285aa1014777285e418a49c79a9547c90133840 Mon Sep 17 00:00:00 2001 From: Glorou <93338547+Glorou@users.noreply.github.com> Date: Mon, 9 Feb 2026 10:50:46 -0500 Subject: [PATCH 89/99] Clean up FileDialogManager by removing unused code Removed unused GetCurrentPath method and unnecessary using directives. --- Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs index 5e0a03b66..8cf0baa2c 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using Dalamud.Bindings.ImGui; -using FFXIVClientStructs; - namespace Dalamud.Interface.ImGuiFileDialog; /// @@ -27,7 +25,6 @@ public class FileDialogManager #pragma warning restore SA1401 #pragma warning restore SA1201 - private FileDialog? dialog; private Action? callback; private Action>? multiCallback; @@ -180,11 +177,6 @@ public class FileDialogManager this.multiCallback = null; } - public string? GetCurrentPath() - { - return this.dialog?.GetCurrentPath(); - } - private void OnSelectionChange(object sender, string path) => this.SelectionChanged?.Invoke(sender, path); private void SetDialog( From e2297661f30c852932aee1b000002aee4bd91e0a Mon Sep 17 00:00:00 2001 From: Glorou Date: Mon, 9 Feb 2026 11:17:11 -0500 Subject: [PATCH 90/99] Added doc --- Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs b/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs index 8cf0baa2c..7332cd735 100644 --- a/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs +++ b/Dalamud/Interface/ImGuiFileDialog/FileDialogManager.cs @@ -30,6 +30,10 @@ public class FileDialogManager private Action>? multiCallback; private string savedPath = "."; + /// + /// Event fires when a new file is selected by the user + /// + /// Returns the path of the file as a string public event EventHandler? SelectionChanged; /// @@ -208,7 +212,6 @@ public class FileDialogManager } this.dialog = new FileDialog(id, title, filters, path, defaultFileName, defaultExtension, selectionCountMax, isModal, flags); - if (this.GetDefaultSortOrder is not null) { try From 3de8c511bf3990e7efa9eb049df60e9e02cf9e79 Mon Sep 17 00:00:00 2001 From: balloon41 Date: Tue, 10 Feb 2026 13:37:58 -0600 Subject: [PATCH 91/99] Update IPlayerState.cs (#2617) Fixed type in BaseRestedExperience summary --- Dalamud/Plugin/Services/IPlayerState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Plugin/Services/IPlayerState.cs b/Dalamud/Plugin/Services/IPlayerState.cs index 21d88010b..838d5a346 100644 --- a/Dalamud/Plugin/Services/IPlayerState.cs +++ b/Dalamud/Plugin/Services/IPlayerState.cs @@ -159,7 +159,7 @@ public interface IPlayerState : IDalamudService RowRef FreeAetheryte { get; } /// - /// Gets the amount of received player commendations of the local player. + /// Gets the amount of rested experience available to the local player. /// uint BaseRestedExperience { get; } From 0a070970a07fd9f3c22bd03c6fd254a68cdc374f Mon Sep 17 00:00:00 2001 From: marzent Date: Wed, 11 Feb 2026 13:03:32 +0100 Subject: [PATCH 92/99] Fix troubleshooting json error on non-Windows platforms --- Dalamud/Support/Troubleshooting.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Dalamud/Support/Troubleshooting.cs b/Dalamud/Support/Troubleshooting.cs index f9e084db8..779754ee8 100644 --- a/Dalamud/Support/Troubleshooting.cs +++ b/Dalamud/Support/Troubleshooting.cs @@ -90,8 +90,7 @@ public static class Troubleshooting File.WriteAllText( Path.Join( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - "XIVLauncher", + startInfo.LogPath, "dalamud.troubleshooting.json"), JsonConvert.SerializeObject(payload, Formatting.Indented)); } From 49e281e57376da85346be3fb97f402ba4c020cfa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 12 Feb 2026 19:10:35 +0000 Subject: [PATCH 93/99] Update ClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 28421f946..a97e9f89d 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 28421f946ae9ec262630f04b2b4a114b54527ff9 +Subproject commit a97e9f89d72d40eabd0f3b52266862dca3eba872 From abe27891c3ed07bf7be73bc7f19221945108afcc Mon Sep 17 00:00:00 2001 From: goat <16760685+goaaats@users.noreply.github.com> Date: Thu, 12 Feb 2026 20:45:23 +0100 Subject: [PATCH 94/99] Tidy tidy --- DalamudCrashHandler/DalamudCrashHandler.cpp | 32 +++++---------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/DalamudCrashHandler/DalamudCrashHandler.cpp b/DalamudCrashHandler/DalamudCrashHandler.cpp index 165cce26d..81b37992b 100644 --- a/DalamudCrashHandler/DalamudCrashHandler.cpp +++ b/DalamudCrashHandler/DalamudCrashHandler.cpp @@ -473,20 +473,17 @@ void open_folder_and_select_items(HWND hwndOpener, const std::wstring& path) { ILFree(piid); } -std::vector EnumerateAdapters(void) +std::vector enum_dxgi_adapters() { - IDXGIAdapter1* pAdapter; - std::vector vAdapters; + std::vector vAdapters; + IDXGIFactory1* pFactory = NULL; - - - // Create a DXGIFactory object. if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&pFactory))) { return vAdapters; } - + IDXGIAdapter1* pAdapter; for (UINT i = 0; pFactory->EnumAdapters1(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i) @@ -501,7 +498,6 @@ std::vector EnumerateAdapters(void) } return vAdapters; - } void export_tspack(HWND hWndParent, const std::filesystem::path& logDir, const std::string& crashLog, const std::string& troubleshootingPackData) { @@ -1057,26 +1053,12 @@ int main() { log << std::format(L"CPU Vendor: {}", vendor) << std::endl; log << std::format(L"CPU Brand: {}", brand) << std::endl; - std::vector availableAdapters = EnumerateAdapters(); - - for (int i = 0; i < availableAdapters.size(); i++) { - auto& myAdapter = *availableAdapters[i]; - auto adapterDescription = DXGI_ADAPTER_DESC1(); - myAdapter.GetDesc1(&adapterDescription); - // Print description to console here + for (IDXGIAdapter1* adapter : enum_dxgi_adapters()) { + DXGI_ADAPTER_DESC1 adapterDescription{}; + myAdapter->GetDesc1(&adapterDescription); log << std::format(L"GPU Desc: {}", adapterDescription.Description) << std::endl; } - /* - for_each(availableAdapters.begin(), availableAdapters.end(), [](IDXGIAdapter1* adapter, , std::wostream log) { - auto& myAdapter = *adapter; - auto adapterDescription = DXGI_ADAPTER_DESC1(); - myAdapter.GetDesc1(&adapterDescription); - // Print description to console here - log << std::format(L"GPU Desc: {}", adapterDescription.Description) << std::endl; - }); - */ - log << L"\n" << stackTrace << std::endl; if (pProgressDialog) From b1b99bae134b76c954193739a1a848ee30e16d44 Mon Sep 17 00:00:00 2001 From: goat <16760685+goaaats@users.noreply.github.com> Date: Thu, 12 Feb 2026 21:03:38 +0100 Subject: [PATCH 95/99] Use correct variable name --- DalamudCrashHandler/DalamudCrashHandler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/DalamudCrashHandler/DalamudCrashHandler.cpp b/DalamudCrashHandler/DalamudCrashHandler.cpp index 81b37992b..f8cadd82b 100644 --- a/DalamudCrashHandler/DalamudCrashHandler.cpp +++ b/DalamudCrashHandler/DalamudCrashHandler.cpp @@ -491,7 +491,6 @@ std::vector enum_dxgi_adapters() vAdapters.push_back(pAdapter); } - if (pFactory) { pFactory->Release(); @@ -1055,7 +1054,7 @@ int main() { for (IDXGIAdapter1* adapter : enum_dxgi_adapters()) { DXGI_ADAPTER_DESC1 adapterDescription{}; - myAdapter->GetDesc1(&adapterDescription); + adapter->GetDesc1(&adapterDescription); log << std::format(L"GPU Desc: {}", adapterDescription.Description) << std::endl; } From 907b585b75542d72182276da0a53a53b48c266ea Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Fri, 30 Jan 2026 12:18:39 +0100 Subject: [PATCH 96/99] Add support for Achievements to IUnlockState --- Dalamud/Game/UnlockState/UnlockState.cs | 80 +++++++++++++++++++++---- Dalamud/Plugin/Services/IUnlockState.cs | 15 ++++- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/Dalamud/Game/UnlockState/UnlockState.cs b/Dalamud/Game/UnlockState/UnlockState.cs index 5ccd7fadb..8496c898a 100644 --- a/Dalamud/Game/UnlockState/UnlockState.cs +++ b/Dalamud/Game/UnlockState/UnlockState.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Dalamud.Data; using Dalamud.Game.Gui; +using Dalamud.Hooking; using Dalamud.IoC; using Dalamud.IoC.Internal; using Dalamud.Logging.Internal; @@ -16,7 +17,9 @@ using FFXIVClientStructs.FFXIV.Component.Exd; using Lumina.Excel; using Lumina.Excel.Sheets; +using AchievementSheet = Lumina.Excel.Sheets.Achievement; using ActionSheet = Lumina.Excel.Sheets.Action; +using CSAchievement = FFXIVClientStructs.FFXIV.Client.Game.UI.Achievement; using InstanceContentSheet = Lumina.Excel.Sheets.InstanceContent; using PublicContentSheet = Lumina.Excel.Sheets.PublicContent; @@ -30,7 +33,8 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState { private static readonly ModuleLog Log = new(nameof(UnlockState)); - private readonly ConcurrentDictionary> cachedUnlockedRowIds = []; + [ServiceManager.ServiceDependency] + private readonly TargetSigScanner sigScanner = Service.Get(); [ServiceManager.ServiceDependency] private readonly DataManager dataManager = Service.Get(); @@ -44,17 +48,31 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState [ServiceManager.ServiceDependency] private readonly RecipeData recipeData = Service.Get(); + private readonly ConcurrentDictionary> cachedUnlockedRowIds = []; + private readonly Hook setAchievementCompletedHook; + [ServiceManager.ServiceConstructor] private UnlockState() { this.clientState.Login += this.OnLogin; this.clientState.Logout += this.OnLogout; this.gameGui.AgentUpdate += this.OnAgentUpdate; + + this.setAchievementCompletedHook = Hook.FromAddress( + this.sigScanner.ScanText("81 FA ?? ?? ?? ?? 0F 87 ?? ?? ?? ?? 53"), + this.SetAchievementCompletedDetour); + + this.setAchievementCompletedHook.Enable(); } + private delegate void SetAchievementCompletedDelegate(CSAchievement* thisPtr, uint id); + /// public event IUnlockState.UnlockDelegate Unlock; + /// + public bool IsAchievementListLoaded => CSAchievement.Instance()->IsLoaded(); + private bool IsLoaded => PlayerState.Instance()->IsLoaded; /// @@ -63,6 +81,21 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState this.clientState.Login -= this.OnLogin; this.clientState.Logout -= this.OnLogout; this.gameGui.AgentUpdate -= this.OnAgentUpdate; + + this.setAchievementCompletedHook.Dispose(); + } + + /// + public bool IsAchievementComplete(AchievementSheet row) + { + // Only check for login state here as individual Achievements + // may be flagged as complete when you unlock them, regardless + // of whether the full Achievements list was loaded or not. + + if (!this.IsLoaded) + return false; + + return CSAchievement.Instance()->IsComplete((int)row.RowId); } /// @@ -464,6 +497,9 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState if (!this.IsLoaded || rowRef.IsUntyped) return false; + if (rowRef.TryGetValue(out var achievementRow)) + return this.IsAchievementComplete(achievementRow); + if (rowRef.TryGetValue(out var actionRow)) return this.IsActionUnlocked(actionRow); @@ -621,6 +657,16 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState this.Update(); } + private void SetAchievementCompletedDetour(CSAchievement* thisPtr, uint id) + { + this.setAchievementCompletedHook.Original(thisPtr, id); + + if (!this.IsLoaded) + return; + + this.RaiseUnlockSafely((RowRef)LuminaUtils.CreateRef(id)); + } + private void Update() { if (!this.IsLoaded) @@ -628,6 +674,8 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState Log.Verbose("Checking for new unlocks..."); + // Do not check for Achievements here! + this.UpdateUnlocksForSheet(); this.UpdateUnlocksForSheet(); this.UpdateUnlocksForSheet(); @@ -688,7 +736,6 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState // - EmjCostume // Probably not happening, because it requires fetching data from server: - // - Achievements // - Titles // - Bozjan Field Notes // - Support/Phantom Jobs, which require to be in Occult Crescent, because it checks the jobs level for != 0 @@ -712,16 +759,21 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState // Log.Verbose($"Unlock detected: {typeof(T).Name}#{row.RowId}"); - foreach (var action in Delegate.EnumerateInvocationList(this.Unlock)) + this.RaiseUnlockSafely((RowRef)rowRef); + } + } + + private void RaiseUnlockSafely(RowRef rowRef) + { + foreach (var action in Delegate.EnumerateInvocationList(this.Unlock)) + { + try { - try - { - action((RowRef)rowRef); - } - catch (Exception ex) - { - Log.Error(ex, "Exception during raise of {handler}", action.Method); - } + action(rowRef); + } + catch (Exception ex) + { + Log.Error(ex, "Exception during raise of {handler}", action.Method); } } } @@ -751,6 +803,12 @@ internal class UnlockStatePluginScoped : IInternalDisposableService, IUnlockStat /// public event IUnlockState.UnlockDelegate? Unlock; + /// + public bool IsAchievementListLoaded => this.unlockStateService.IsAchievementListLoaded; + + /// + public bool IsAchievementComplete(AchievementSheet row) => this.unlockStateService.IsAchievementComplete(row); + /// public bool IsActionUnlocked(ActionSheet row) => this.unlockStateService.IsActionUnlocked(row); diff --git a/Dalamud/Plugin/Services/IUnlockState.cs b/Dalamud/Plugin/Services/IUnlockState.cs index f51222ba1..29e5186bc 100644 --- a/Dalamud/Plugin/Services/IUnlockState.cs +++ b/Dalamud/Plugin/Services/IUnlockState.cs @@ -1,5 +1,3 @@ -using System.Diagnostics.CodeAnalysis; - using Lumina.Excel; using Lumina.Excel.Sheets; @@ -23,6 +21,19 @@ public interface IUnlockState : IDalamudService /// event UnlockDelegate? Unlock; + /// + /// Gets a value indicating whether the full Achievements list was received. + /// + bool IsAchievementListLoaded { get; } + + /// + /// Determines whether the specified Achievement is completed.
+ /// Requires that the player requested the Achievements list (can be chcked with ). + ///
+ /// The Achievement row to check. + /// if completed; otherwise, . + bool IsAchievementComplete(Achievement row); + /// /// Determines whether the specified Action is unlocked. /// From 1ba18e54bf14fa6475001fa55bbcfab6c42249a2 Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Fri, 30 Jan 2026 12:28:05 +0100 Subject: [PATCH 97/99] Add support for Titles to IUnlockState --- Dalamud/Game/UnlockState/UnlockState.cs | 48 +++++++++++++++++++++++-- Dalamud/Plugin/Services/IUnlockState.cs | 13 +++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/Dalamud/Game/UnlockState/UnlockState.cs b/Dalamud/Game/UnlockState/UnlockState.cs index 8496c898a..273a0228e 100644 --- a/Dalamud/Game/UnlockState/UnlockState.cs +++ b/Dalamud/Game/UnlockState/UnlockState.cs @@ -50,6 +50,7 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState private readonly ConcurrentDictionary> cachedUnlockedRowIds = []; private readonly Hook setAchievementCompletedHook; + private readonly Hook setTitleUnlockedHook; [ServiceManager.ServiceConstructor] private UnlockState() @@ -62,17 +63,27 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState this.sigScanner.ScanText("81 FA ?? ?? ?? ?? 0F 87 ?? ?? ?? ?? 53"), this.SetAchievementCompletedDetour); + this.setTitleUnlockedHook = Hook.FromAddress( + this.sigScanner.ScanText("B8 ?? ?? ?? ?? 66 3B D0 73 ?? 44 0F B7 C2 49 C1 E8 ?? 4C 03 C1 0F B7 C2 83 E0 ?? 41 0F B6 48 ?? 0F AB C1"), + this.SetTitleUnlockedDetour); + this.setAchievementCompletedHook.Enable(); + this.setTitleUnlockedHook.Enable(); } private delegate void SetAchievementCompletedDelegate(CSAchievement* thisPtr, uint id); + private delegate void SetTitleUnlockedDelegate(TitleList* thisPtr, ushort id); + /// public event IUnlockState.UnlockDelegate Unlock; /// public bool IsAchievementListLoaded => CSAchievement.Instance()->IsLoaded(); + /// + public bool IsTitleListLoaded => UIState.Instance()->TitleList.DataReceived; + private bool IsLoaded => PlayerState.Instance()->IsLoaded; /// @@ -448,6 +459,19 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState return PlayerState.Instance()->IsSecretRecipeBookUnlocked(row.RowId); } + /// + public bool IsTitleUnlocked(Title row) + { + // Only check for login state here as individual Titles + // may be flagged as complete when you unlock them, regardless + // of whether the full Titles list was loaded or not. + + if (!this.IsLoaded) + return false; + + return UIState.Instance()->TitleList.IsTitleUnlocked((ushort)row.RowId); + } + /// public bool IsTraitUnlocked(Trait row) { @@ -608,6 +632,9 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState if (rowRef.TryGetValue(out var secretRecipeBookRow)) return this.IsSecretRecipeBookUnlocked(secretRecipeBookRow); + if (rowRef.TryGetValue(out var titleRow)) + return this.IsTitleUnlocked(titleRow); + if (rowRef.TryGetValue<Trait>(out var traitRow)) return this.IsTraitUnlocked(traitRow); @@ -667,14 +694,24 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState this.RaiseUnlockSafely((RowRef)LuminaUtils.CreateRef<AchievementSheet>(id)); } + private void SetTitleUnlockedDetour(TitleList* thisPtr, ushort id) + { + this.setTitleUnlockedHook.Original(thisPtr, id); + + if (!this.IsLoaded) + return; + + this.RaiseUnlockSafely((RowRef)LuminaUtils.CreateRef<Title>(id)); + } + private void Update() { if (!this.IsLoaded) return; Log.Verbose("Checking for new unlocks..."); - - // Do not check for Achievements here! + + // Do not check for Achievements or Titles here! this.UpdateUnlocksForSheet<ActionSheet>(); this.UpdateUnlocksForSheet<AetherCurrent>(); @@ -736,7 +773,6 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState // - EmjCostume // Probably not happening, because it requires fetching data from server: - // - Titles // - Bozjan Field Notes // - Support/Phantom Jobs, which require to be in Occult Crescent, because it checks the jobs level for != 0 } @@ -806,6 +842,9 @@ internal class UnlockStatePluginScoped : IInternalDisposableService, IUnlockStat /// <inheritdoc/> public bool IsAchievementListLoaded => this.unlockStateService.IsAchievementListLoaded; + /// <inheritdoc/> + public bool IsTitleListLoaded => this.unlockStateService.IsTitleListLoaded; + /// <inheritdoc/> public bool IsAchievementComplete(AchievementSheet row) => this.unlockStateService.IsAchievementComplete(row); @@ -932,6 +971,9 @@ internal class UnlockStatePluginScoped : IInternalDisposableService, IUnlockStat /// <inheritdoc/> public bool IsSecretRecipeBookUnlocked(SecretRecipeBook row) => this.unlockStateService.IsSecretRecipeBookUnlocked(row); + /// <inheritdoc/> + public bool IsTitleUnlocked(Title row) => this.unlockStateService.IsTitleUnlocked(row); + /// <inheritdoc/> public bool IsTraitUnlocked(Trait row) => this.unlockStateService.IsTraitUnlocked(row); diff --git a/Dalamud/Plugin/Services/IUnlockState.cs b/Dalamud/Plugin/Services/IUnlockState.cs index 29e5186bc..4554aa318 100644 --- a/Dalamud/Plugin/Services/IUnlockState.cs +++ b/Dalamud/Plugin/Services/IUnlockState.cs @@ -26,6 +26,11 @@ public interface IUnlockState : IDalamudService /// </summary> bool IsAchievementListLoaded { get; } + /// <summary> + /// Gets a value indicating whether the full Titles list was received. + /// </summary> + bool IsTitleListLoaded { get; } + /// <summary> /// Determines whether the specified Achievement is completed.<br/> /// Requires that the player requested the Achievements list (can be chcked with <see cref="IsAchievementListLoaded"/>). @@ -322,6 +327,14 @@ public interface IUnlockState : IDalamudService /// <returns><see langword="true"/> if unlocked; otherwise, <see langword="false"/>.</returns> bool IsSecretRecipeBookUnlocked(SecretRecipeBook row); + /// <summary> + /// Determines whether the specified Title is unlocked.<br/> + /// Requires that the player requested the Titles list (can be chcked with <see cref="IsTitleListLoaded"/>). + /// </summary> + /// <param name="row">The Title row to check.</param> + /// <returns><see langword="true"/> if unlocked; otherwise, <see langword="false"/>.</returns> + bool IsTitleUnlocked(Title row); + /// <summary> /// Determines whether the specified Trait is unlocked. /// </summary> From 46513978087cc11b647fa6a39552be986dd96819 Mon Sep 17 00:00:00 2001 From: Haselnussbomber <mail@haselnussbomber.de> Date: Fri, 30 Jan 2026 12:57:08 +0100 Subject: [PATCH 98/99] Add support for Adventures to IUnlockState --- Dalamud/Game/UnlockState/UnlockState.cs | 19 +++++++++++++++++-- Dalamud/Plugin/Services/IUnlockState.cs | 7 +++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Dalamud/Game/UnlockState/UnlockState.cs b/Dalamud/Game/UnlockState/UnlockState.cs index 273a0228e..7e8f64adf 100644 --- a/Dalamud/Game/UnlockState/UnlockState.cs +++ b/Dalamud/Game/UnlockState/UnlockState.cs @@ -115,6 +115,15 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState return this.IsUnlockLinkUnlocked(row.UnlockLink.RowId); } + /// <inheritdoc/> + public bool IsAdventureComplete(Adventure row) + { + if (!this.IsLoaded) + return false; + + return PlayerState.Instance()->IsAdventureComplete(row.RowId - 0x210000); + } + /// <inheritdoc/> public bool IsAetherCurrentUnlocked(AetherCurrent row) { @@ -527,6 +536,9 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState if (rowRef.TryGetValue<ActionSheet>(out var actionRow)) return this.IsActionUnlocked(actionRow); + if (rowRef.TryGetValue<Adventure>(out var adventureRow)) + return this.IsAdventureComplete(adventureRow); + if (rowRef.TryGetValue<AetherCurrent>(out var aetherCurrentRow)) return this.IsAetherCurrentUnlocked(aetherCurrentRow); @@ -710,10 +722,11 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState return; Log.Verbose("Checking for new unlocks..."); - + // Do not check for Achievements or Titles here! this.UpdateUnlocksForSheet<ActionSheet>(); + this.UpdateUnlocksForSheet<Adventure>(); this.UpdateUnlocksForSheet<AetherCurrent>(); this.UpdateUnlocksForSheet<AetherCurrentCompFlgSet>(); this.UpdateUnlocksForSheet<AozAction>(); @@ -760,7 +773,6 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState // For some other day: // - FishingSpot // - Spearfishing - // - Adventure (Sightseeing) // - MinerFolkloreTome // - BotanistFolkloreTome // - FishingFolkloreTome @@ -851,6 +863,9 @@ internal class UnlockStatePluginScoped : IInternalDisposableService, IUnlockStat /// <inheritdoc/> public bool IsActionUnlocked(ActionSheet row) => this.unlockStateService.IsActionUnlocked(row); + /// <inheritdoc/> + public bool IsAdventureComplete(Adventure row) => this.unlockStateService.IsAdventureComplete(row); + /// <inheritdoc/> public bool IsAetherCurrentCompFlgSetUnlocked(AetherCurrentCompFlgSet row) => this.unlockStateService.IsAetherCurrentCompFlgSetUnlocked(row); diff --git a/Dalamud/Plugin/Services/IUnlockState.cs b/Dalamud/Plugin/Services/IUnlockState.cs index 4554aa318..4f92b2b3d 100644 --- a/Dalamud/Plugin/Services/IUnlockState.cs +++ b/Dalamud/Plugin/Services/IUnlockState.cs @@ -46,6 +46,13 @@ public interface IUnlockState : IDalamudService /// <returns><see langword="true"/> if unlocked; otherwise, <see langword="false"/>.</returns> bool IsActionUnlocked(Lumina.Excel.Sheets.Action row); + /// <summary> + /// Determines whether the specified Adventure is completed. + /// </summary> + /// <param name="row">The Adventure row to check.</param> + /// <returns><see langword="true"/> if completed; otherwise, <see langword="false"/>.</returns> + public bool IsAdventureComplete(Adventure row); + /// <summary> /// Determines whether the specified AetherCurrentCompFlgSet is unlocked. /// </summary> From 1779d2681ad5d800febbd4c63e7037fae9925da6 Mon Sep 17 00:00:00 2001 From: Haselnussbomber <mail@haselnussbomber.de> Date: Sat, 31 Jan 2026 22:16:07 +0100 Subject: [PATCH 99/99] Switch to CS in UnlockState --- Dalamud/Game/UnlockState/UnlockState.cs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/Dalamud/Game/UnlockState/UnlockState.cs b/Dalamud/Game/UnlockState/UnlockState.cs index 7e8f64adf..4b83e114a 100644 --- a/Dalamud/Game/UnlockState/UnlockState.cs +++ b/Dalamud/Game/UnlockState/UnlockState.cs @@ -33,9 +33,6 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState { private static readonly ModuleLog Log = new(nameof(UnlockState)); - [ServiceManager.ServiceDependency] - private readonly TargetSigScanner sigScanner = Service<TargetSigScanner>.Get(); - [ServiceManager.ServiceDependency] private readonly DataManager dataManager = Service<DataManager>.Get(); @@ -49,8 +46,8 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState private readonly RecipeData recipeData = Service<RecipeData>.Get(); private readonly ConcurrentDictionary<Type, HashSet<uint>> cachedUnlockedRowIds = []; - private readonly Hook<SetAchievementCompletedDelegate> setAchievementCompletedHook; - private readonly Hook<SetTitleUnlockedDelegate> setTitleUnlockedHook; + private readonly Hook<CSAchievement.Delegates.SetAchievementCompleted> setAchievementCompletedHook; + private readonly Hook<TitleList.Delegates.SetTitleUnlocked> setTitleUnlockedHook; [ServiceManager.ServiceConstructor] private UnlockState() @@ -59,22 +56,18 @@ internal unsafe class UnlockState : IInternalDisposableService, IUnlockState this.clientState.Logout += this.OnLogout; this.gameGui.AgentUpdate += this.OnAgentUpdate; - this.setAchievementCompletedHook = Hook<SetAchievementCompletedDelegate>.FromAddress( - this.sigScanner.ScanText("81 FA ?? ?? ?? ?? 0F 87 ?? ?? ?? ?? 53"), + this.setAchievementCompletedHook = Hook<CSAchievement.Delegates.SetAchievementCompleted>.FromAddress( + (nint)CSAchievement.MemberFunctionPointers.SetAchievementCompleted, this.SetAchievementCompletedDetour); - this.setTitleUnlockedHook = Hook<SetTitleUnlockedDelegate>.FromAddress( - this.sigScanner.ScanText("B8 ?? ?? ?? ?? 66 3B D0 73 ?? 44 0F B7 C2 49 C1 E8 ?? 4C 03 C1 0F B7 C2 83 E0 ?? 41 0F B6 48 ?? 0F AB C1"), + this.setTitleUnlockedHook = Hook<TitleList.Delegates.SetTitleUnlocked>.FromAddress( + (nint)TitleList.MemberFunctionPointers.SetTitleUnlocked, this.SetTitleUnlockedDetour); this.setAchievementCompletedHook.Enable(); this.setTitleUnlockedHook.Enable(); } - private delegate void SetAchievementCompletedDelegate(CSAchievement* thisPtr, uint id); - - private delegate void SetTitleUnlockedDelegate(TitleList* thisPtr, ushort id); - /// <inheritdoc/> public event IUnlockState.UnlockDelegate Unlock;