From db5f27518fb6ec50cdfa5d6dcd39e10cbb4f1fd7 Mon Sep 17 00:00:00 2001 From: CMDRNuffin <4348470+CMDRNuffin@users.noreply.github.com> Date: Fri, 19 Dec 2025 01:24:43 +0100 Subject: [PATCH 1/7] Prevent ImGui text box methods from cloning unchanged input every frame The overloads taking a string by ref for the input text of the various ways to display a text box would all take the input string, copy it into a buffer for imgui and then unconditionally produce a new string once the imgui call returned. Now we only create a new string when the return value of the native function actually indicates that the text changed. This makes the GC happy, and also users like me who like to make the GC happy. Other side effects: The assumption that the reference doesn't change if the method returns false, which is very reasonable IMO, is now correct. --- .../Custom/ImGui.Manual.cs | 153 ++++++++++++++---- 1 file changed, 119 insertions(+), 34 deletions(-) diff --git a/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Manual.cs b/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Manual.cs index 89b3cc3d6..ce1bf961d 100644 --- a/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Manual.cs +++ b/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Manual.cs @@ -127,8 +127,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputText(label, t.Buffer[..(maxLength + 1)], flags, callback); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -140,8 +145,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputText(label, t.Buffer[..(maxLength + 1)], flags, callback); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -153,8 +163,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputText(label, t.Buffer[..(maxLength + 1)], flags, callback, ref context); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -166,8 +181,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputText(label, t.Buffer[..(maxLength + 1)], flags, callback, in context); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -287,8 +307,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextEx(label, hint, t.Buffer[..(maxLength + 1)], sizeArg, flags, callback); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -300,8 +325,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextEx(label, hint, t.Buffer[..(maxLength + 1)], sizeArg, flags, callback); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -314,8 +344,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextEx(label, hint, t.Buffer[..(maxLength + 1)], sizeArg, flags, callback, ref context); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -328,8 +363,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextEx(label, hint, t.Buffer[..(maxLength + 1)], sizeArg, flags, callback, in context); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -388,8 +428,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextMultiline(label, t.Buffer[..(maxLength + 1)], size, flags, callback); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -401,8 +446,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextMultiline(label, t.Buffer[..(maxLength + 1)], size, flags, callback); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -414,8 +464,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextMultiline(label, t.Buffer[..(maxLength + 1)], size, flags, callback, ref context); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -427,8 +482,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextMultiline(label, t.Buffer[..(maxLength + 1)], size, flags, callback, in context); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -477,8 +537,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextWithHint(label, hint, t.Buffer[..(maxLength + 1)], flags, callback); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -490,8 +555,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextWithHint(label, hint, t.Buffer[..(maxLength + 1)], flags, callback); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -503,8 +573,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextWithHint(label, hint, t.Buffer[..(maxLength + 1)], flags, callback, ref context); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -516,8 +591,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = InputTextWithHint(label, hint, t.Buffer[..(maxLength + 1)], flags, callback, in context); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } @@ -541,8 +621,13 @@ public unsafe partial class ImGui var t = new ImU8String(buf); t.Reserve(maxLength + 1); var r = TempInputText(bb, id, label, t.Buffer[..(maxLength + 1)], flags); - var i = t.Buffer.IndexOf((byte)0); - buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + + if (r) + { + var i = t.Buffer.IndexOf((byte)0); + buf = Encoding.UTF8.GetString(i == -1 ? t.Buffer : t.Buffer[..i]); + } + t.Recycle(); return r; } From 86e12f411d672a511ee3e51d6660ce3b6f4f489c Mon Sep 17 00:00:00 2001 From: Haselnussbomber Date: Fri, 19 Dec 2025 03:26:53 +0100 Subject: [PATCH 2/7] Update UIColor widget --- .../Windows/Data/Widgets/UIColorWidget.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs index e52a291ef..3550f053c 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UIColorWidget.cs @@ -44,7 +44,7 @@ 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, 5)) + if (!ImGui.BeginTable("UIColor"u8, 7)) return; ImGui.TableSetupScrollFreeze(0, 1); @@ -62,6 +62,8 @@ internal class UiColorWidget : IDataWindowWidget ImGui.TableSetupColumn("Light"u8, ImGuiTableColumnFlags.WidthFixed, colorw); ImGui.TableSetupColumn("Classic FF"u8, ImGuiTableColumnFlags.WidthFixed, colorw); ImGui.TableSetupColumn("Clear Blue"u8, ImGuiTableColumnFlags.WidthFixed, colorw); + ImGui.TableSetupColumn("Clear White"u8, ImGuiTableColumnFlags.WidthFixed, colorw); + ImGui.TableSetupColumn("Clear Green"u8, ImGuiTableColumnFlags.WidthFixed, colorw); ImGui.TableHeadersRow(); var clipper = ImGui.ImGuiListClipper(); @@ -120,6 +122,22 @@ internal class UiColorWidget : IDataWindowWidget adjacentRow.HasValue) DrawEdgePreview(id, row.ClearBlue, adjacentRow.Value.ClearBlue); ImGui.PopID(); + + ImGui.TableNextColumn(); + ImGui.AlignTextToFramePadding(); + ImGui.PushID($"row{id}_white"); + if (this.DrawColorColumn(row.Unknown0) && + adjacentRow.HasValue) + DrawEdgePreview(id, row.Unknown0, adjacentRow.Value.Unknown0); + ImGui.PopID(); + + ImGui.TableNextColumn(); + ImGui.AlignTextToFramePadding(); + ImGui.PushID($"row{id}_green"); + if (this.DrawColorColumn(row.Unknown1) && + adjacentRow.HasValue) + DrawEdgePreview(id, row.Unknown1, adjacentRow.Value.Unknown1); + ImGui.PopID(); } } From 7af0523e886f314461229067a541c993f1498e43 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 19 Dec 2025 06:38:57 +0000 Subject: [PATCH 3/7] Update ClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index f60c282d6..7227f6b12 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit f60c282d63b4157a8f8fb7cbb7e0b35361cdaa12 +Subproject commit 7227f6b1222d1149e0b2e26d2dc31acf341df1cc From f3f4ced0495781bedd04d0345576f695699c4bb6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 19 Dec 2025 06:39:07 +0000 Subject: [PATCH 4/7] 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 d8d0b53e2..7d3f90e61 160000 --- a/lib/Lumina.Excel +++ b/lib/Lumina.Excel @@ -1 +1 @@ -Subproject commit d8d0b53e27393f509ac5397511cb8d251d562277 +Subproject commit 7d3f90e61732df6aef63196d1abaab1074f6f3c9 From 89c46944b6832e6e562009c6aa756a5b871fef2f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 19 Dec 2025 10:20:39 +0000 Subject: [PATCH 5/7] Update ClientStructs --- lib/FFXIVClientStructs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index 7227f6b12..faf803a76 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit 7227f6b1222d1149e0b2e26d2dc31acf341df1cc +Subproject commit faf803a76813511768d45c137a543aaacf5420b8 From 4ddaaf3809e82adab97d6761931ece609b7f7c2f Mon Sep 17 00:00:00 2001 From: wolfcomp <4028289+wolfcomp@users.noreply.github.com> Date: Fri, 19 Dec 2025 11:41:33 +0100 Subject: [PATCH 6/7] Add new themes and update themed path logic --- .../Interface/Internal/Windows/Data/Widgets/UldWidget.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs index bc12f4d28..019154b53 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs @@ -26,8 +26,8 @@ namespace Dalamud.Interface.Internal.Windows.Data.Widgets; internal class UldWidget : IDataWindowWidget { // 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"]; - private static readonly string[] ThemeBasePaths = ["ui/uld/", "ui/uld/img01/", "ui/uld/img02/", "ui/uld/img03/"]; + 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 +263,7 @@ internal class UldWidget : IDataWindowWidget } private string ToThemedPath(string path) => - ThemeBasePaths[this.selectedTheme] + path[ThemeBasePaths[0].Length..]; + this.UldBaseBath + (this.selectedTheme > 0 ? $"img{this.selectedTheme:D2}" : "") + path[this.UldBaseBath.Length..]; private void DrawTextureEntry(UldRoot.TextureEntry textureEntry, TextureManager textureManager) { From c71d8889d791a3ba48dcb290c37ce63f148e70de Mon Sep 17 00:00:00 2001 From: wolfcomp <4028289+wolfcomp@users.noreply.github.com> Date: Fri, 19 Dec 2025 11:51:09 +0100 Subject: [PATCH 7/7] Access const as non instance --- Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs index 019154b53..4d858922a 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/UldWidget.cs @@ -263,7 +263,7 @@ internal class UldWidget : IDataWindowWidget } private string ToThemedPath(string path) => - this.UldBaseBath + (this.selectedTheme > 0 ? $"img{this.selectedTheme:D2}" : "") + path[this.UldBaseBath.Length..]; + UldBaseBath + (this.selectedTheme > 0 ? $"img{this.selectedTheme:D2}" : "") + path[UldBaseBath.Length..]; private void DrawTextureEntry(UldRoot.TextureEntry textureEntry, TextureManager textureManager) {