diff --git a/ChatTwo/ChatTwo.csproj b/ChatTwo/ChatTwo.csproj index 37c8c38..0254e6d 100755 --- a/ChatTwo/ChatTwo.csproj +++ b/ChatTwo/ChatTwo.csproj @@ -1,6 +1,6 @@ - 1.29.8 + 1.29.9 net8.0-windows enable enable diff --git a/ChatTwo/FontManager.cs b/ChatTwo/FontManager.cs index 1172220..6e08346 100644 --- a/ChatTwo/FontManager.cs +++ b/ChatTwo/FontManager.cs @@ -20,7 +20,6 @@ public class FontManager private ushort[] Ranges; private ushort[] JpRange; - private readonly ushort[] SymRange = [0xE020, 0xE0DB, 0]; public static readonly HashSet AxisFontSizeList = @@ -123,8 +122,7 @@ public class FontManager Plugin.Config.JapaneseFontV2.FontId.AddToBuildToolkit(tk, config); config.SizePt = Plugin.Config.SymbolsFontSizeV2; - config.GlyphRanges = SymRange; - tk.AddFontFromMemory(GameSymFont, config, "ChatTwo2 Sym Font"); + tk.AddGameSymbol(config); tk.Font = config.MergeFont; } @@ -144,8 +142,7 @@ public class FontManager Plugin.Config.JapaneseFontV2.FontId.AddToBuildToolkit(tk, config); config.SizePt = Plugin.Config.SymbolsFontSizeV2; - config.GlyphRanges = SymRange; - tk.AddFontFromMemory(GameSymFont, config, "ChatTwo2 Sym Font"); + tk.AddGameSymbol(config); tk.Font = config.MergeFont; } diff --git a/ChatTwo/GameFunctions/ChatBox.cs b/ChatTwo/GameFunctions/ChatBox.cs index efbdc57..b129a07 100644 --- a/ChatTwo/GameFunctions/ChatBox.cs +++ b/ChatTwo/GameFunctions/ChatBox.cs @@ -1,32 +1,20 @@ using System.Text; -using Dalamud.Utility.Signatures; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI; namespace ChatTwo.GameFunctions; // From: https://git.anna.lgbt/anna/XivCommon/src/branch/main/XivCommon/Functions/Chat.cs -public unsafe class ChatCommon +public unsafe class ChatBox { - [Signature("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 48 8B F2 48 8B F9 45 84 C9")] - private readonly delegate* unmanaged ProcessChatBox = null!; - - internal ChatCommon() + public static void SendMessageUnsafe(byte[] message) { - Plugin.GameInteropProvider.InitializeFromAttributes(this); - } - - public void SendMessageUnsafe(byte[] message) - { - if (ProcessChatBox == null) - throw new InvalidOperationException("Could not find signature for chat sending"); - var mes = Utf8String.FromSequence(message); - ProcessChatBox(UIModule.Instance(), mes, IntPtr.Zero, 0); + UIModule.Instance()->ProcessChatBoxEntry(mes); mes->Dtor(true); } - public void SendMessage(string message) + public static void SendMessage(string message) { var bytes = Encoding.UTF8.GetBytes(message); if (bytes.Length == 0) @@ -45,7 +33,7 @@ public unsafe class ChatCommon { var uText = Utf8String.FromString(text); - uText->SanitizeString( 0x27F, (Utf8String*)nint.Zero); + uText->SanitizeString(0x27F, (Utf8String*)nint.Zero); var sanitised = uText->ToString(); uText->Dtor(true); diff --git a/ChatTwo/GameFunctions/GameFunctions.cs b/ChatTwo/GameFunctions/GameFunctions.cs index a9aceea..14844f4 100755 --- a/ChatTwo/GameFunctions/GameFunctions.cs +++ b/ChatTwo/GameFunctions/GameFunctions.cs @@ -12,6 +12,7 @@ using FFXIVClientStructs.FFXIV.Client.UI.Info; using FFXIVClientStructs.FFXIV.Component.GUI; using Lumina.Excel; using Lumina.Excel.Sheets; + using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; namespace ChatTwo.GameFunctions; @@ -66,10 +67,10 @@ internal unsafe class GameFunctions : IDisposable var worldName = row.Name.ExtractText(); ReplacementName = $"{name}@{worldName}"; - Plugin.Common.SendMessage($"/{commandName} add {Placeholder}"); + ChatBox.SendMessage($"/{commandName} add {Placeholder}"); } - internal static T* GetAddon(string name) where T : unmanaged + private static T* GetAddon(string name) where T : unmanaged { var addon = RaptureAtkModule.Instance()->RaptureAtkUnitManager.GetAddonByName(name); return addon != null && addon->IsReady ? (T*)addon : null; diff --git a/ChatTwo/Plugin.cs b/ChatTwo/Plugin.cs index f63ddee..e9dab48 100755 --- a/ChatTwo/Plugin.cs +++ b/ChatTwo/Plugin.cs @@ -1,7 +1,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using ChatTwo.GameFunctions; using ChatTwo.Http; using ChatTwo.Ipc; using ChatTwo.Resources; @@ -53,7 +52,6 @@ public sealed class Plugin : IDalamudPlugin public DebuggerWindow DebuggerWindow { get; } internal Commands Commands { get; } - internal ChatCommon Common { get; } internal GameFunctions.GameFunctions Functions { get; } internal MessageManager MessageManager { get; } internal IpcManager Ipc { get; } @@ -97,7 +95,6 @@ public sealed class Plugin : IDalamudPlugin ServerCore = new ServerCore(this); Commands = new Commands(this); - Common = new ChatCommon(); Functions = new GameFunctions.GameFunctions(this); Ipc = new IpcManager(); ExtraChat = new ExtraChat(this); diff --git a/ChatTwo/Ui/ChatLogWindow.cs b/ChatTwo/Ui/ChatLogWindow.cs index d3e0eda..e6ea4ba 100644 --- a/ChatTwo/Ui/ChatLogWindow.cs +++ b/ChatTwo/Ui/ChatLogWindow.cs @@ -877,7 +877,7 @@ public sealed class ChatLogWindow : Window // registers stub handlers and actually processes its commands in a // SendMessage detour. var bytes = Encoding.UTF8.GetBytes(channel.Value.Prefix()); - Plugin.Common.SendMessageUnsafe(bytes); + ChatBox.SendMessageUnsafe(bytes); return; } @@ -921,7 +921,7 @@ public sealed class ChatLogWindow : Window var tellBytes = Encoding.UTF8.GetBytes(trimmed); AutoTranslate.ReplaceWithPayload(ref tellBytes); - Plugin.Common.SendMessageUnsafe(tellBytes); + ChatBox.SendMessageUnsafe(tellBytes); Chat = string.Empty; return; @@ -949,14 +949,14 @@ public sealed class ChatLogWindow : Window if (activeTab.CurrentChannel.UseTempChannel) trimmed = $"{activeTab.CurrentChannel.TempChannel.Prefix()} {trimmed}"; - else // (activeTab is { Channel: { } channel }) TODO Check this channel selection + else trimmed = $"{activeTab.CurrentChannel.Channel.Prefix()} {trimmed}"; } var bytes = Encoding.UTF8.GetBytes(trimmed); AutoTranslate.ReplaceWithPayload(ref bytes); - Plugin.Common.SendMessageUnsafe(bytes); + ChatBox.SendMessageUnsafe(bytes); } Chat = string.Empty; diff --git a/ChatTwo/Ui/Debugger.cs b/ChatTwo/Ui/Debugger.cs index a4bbecd..82eaa5b 100644 --- a/ChatTwo/Ui/Debugger.cs +++ b/ChatTwo/Ui/Debugger.cs @@ -1,6 +1,5 @@ using System.Numerics; using Dalamud.Interface.Windowing; -using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using ImGuiNET; diff --git a/ChatTwo/Ui/SeStringDebugger.cs b/ChatTwo/Ui/SeStringDebugger.cs index 150df99..5be7138 100644 --- a/ChatTwo/Ui/SeStringDebugger.cs +++ b/ChatTwo/Ui/SeStringDebugger.cs @@ -1,12 +1,13 @@ -using System.Numerics; +using System.Globalization; +using System.Numerics; using System.Text; using ChatTwo.Util; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling.Payloads; +using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; using ImGuiNET; -using Lumina.Excel; -using Lumina.Excel.Sheets; + using DalamudPartyFinderPayload = Dalamud.Game.Text.SeStringHandling.Payloads.PartyFinderPayload; namespace ChatTwo.Ui; @@ -15,7 +16,7 @@ public class SeStringDebugger : Window { private readonly Plugin Plugin; - public SeStringDebugger(Plugin plugin) : base($"SeString Debugger###chat2-sestringdebugger") + public SeStringDebugger(Plugin plugin) : base("SeString Debugger###chat2-sestringdebugger") { Plugin = plugin; @@ -92,8 +93,8 @@ public class SeStringDebugger : Window { "TerritoryType.RowId", map.TerritoryType.RowId.ToString() }, { "RawX", map.RawX.ToString() }, { "RawY", map.RawY.ToString() }, - { "XCoord", map.XCoord.ToString() }, - { "YCoord", map.YCoord.ToString() }, + { "XCoord", map.XCoord.ToString(CultureInfo.InvariantCulture) }, + { "YCoord", map.YCoord.ToString(CultureInfo.InvariantCulture) }, { "CoordinateString", map.CoordinateString }, { "DataString", map.DataString }, }); @@ -160,7 +161,7 @@ public class SeStringDebugger : Window } case IconPayload icon: { - var found = IconUtil.GfdFileView.TryGetEntry((uint) icon.Icon, out var entry); + var found = IconUtil.GfdFileView.TryGetEntry((uint) icon.Icon, out _); RenderMetadataDictionary("Link IconPayload", new Dictionary { { "Found", found.ToString() }, @@ -173,15 +174,12 @@ public class SeStringDebugger : Window var colorPayload = ColorPayload.From(raw.Data); if (colorPayload != null) { - var push = colorPayload.Enabled && colorPayload.Color != 0; - // if (push) ImGui.PushStyleColor(ImGuiCol.Text, ColourUtil.RgbaToAbgr(colorPayload.U)); RenderMetadataDictionary("Link ColorPayload", new Dictionary { { "Unshifted", colorPayload.UnshiftedColor.ToString("X8") }, { "Color", colorPayload.Color.ToString("X8") }, { "Enabled?", colorPayload.Enabled.ToString() }, }); - // if (push) ImGui.PopStyleColor(); } else { @@ -289,10 +287,8 @@ public class SeStringDebugger : Window { if (string.IsNullOrEmpty(original)) { - var str = original == null ? "(null)" : "(empty)"; - ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1, 1, 1, 0.5f)); - ImGui.TextUnformatted(str); - ImGui.PopStyleColor(); + using var pushedColor = ImRaii.PushColor(ImGuiCol.Text, new Vector4(1, 1, 1, 0.5f)); + ImGui.TextUnformatted(original == null ? "(null)" : "(empty)"); return; } @@ -300,46 +296,35 @@ public class SeStringDebugger : Window var start = 0; var end = text.Length; - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(0, 0)); + using var pushedStyle = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(0, 0)); - void WriteText(string text) + void WriteText(string wText) { if (wrap) - { - ImGui.TextWrapped(text); - } + ImGui.TextWrapped(wText); else - { - ImGui.TextUnformatted(text); - } + ImGui.TextUnformatted(wText); } while (start < end && char.IsWhiteSpace(text[start])) - { start++; - } + if (start > 0) { - ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1, 1, 1, 0.5f)); + using var pushedColor = ImRaii.PushColor(ImGuiCol.Text, new Vector4(1, 1, 1, 0.5f)); WriteText(new string('_', start)); - ImGui.PopStyleColor(); ImGui.SameLine(); } while (end > start && char.IsWhiteSpace(text[end - 1])) - { end--; - } WriteText(text[start..end]); if (end < text.Length) { ImGui.SameLine(); - ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1, 1, 1, 0.5f)); + using var pushedColor = ImRaii.PushColor(ImGuiCol.Text, new Vector4(1, 1, 1, 0.5f)); WriteText(new string('_', text.Length - end)); - ImGui.PopStyleColor(); } - - ImGui.PopStyleVar(); } } diff --git a/ChatTwo/Ui/Settings.cs b/ChatTwo/Ui/Settings.cs index 9952a57..b93efae 100755 --- a/ChatTwo/Ui/Settings.cs +++ b/ChatTwo/Ui/Settings.cs @@ -31,21 +31,21 @@ public sealed class SettingsWindow : Window Plugin = plugin; Mutable = new Configuration(); - Tabs = new List - { + Tabs = + [ new Display(Mutable), new ChatLog(Plugin, Mutable), new Emote(Plugin, Mutable), - new Preview(Plugin, Mutable), + new Preview(Mutable), new Fonts(Mutable), new ChatColours(Plugin, Mutable), - new Tabs(Plugin, Mutable), + new Tabs(Mutable), new Database(Plugin, Mutable), new Webinterface(Plugin, Mutable), new Miscellaneous(Mutable), new Changelog(Mutable), - new About(), - }; + new About() + ]; RespectCloseHotkey = false; DisableWindowSounds = true; diff --git a/ChatTwo/Ui/SettingsTabs/About.cs b/ChatTwo/Ui/SettingsTabs/About.cs index f3d7146..ccc0b89 100755 --- a/ChatTwo/Ui/SettingsTabs/About.cs +++ b/ChatTwo/Ui/SettingsTabs/About.cs @@ -13,7 +13,7 @@ internal sealed class About : ISettingsTab { public string Name => string.Format(Language.Options_About_Tab, Plugin.PluginName) + "###tabs-about"; - private readonly List _translators = + private readonly List Translators = [ "q673135110", "Akizem", "d0tiKs", "Moonlight_Everlit", "Dark32", "andreycout", @@ -28,7 +28,7 @@ internal sealed class About : ISettingsTab internal About() { - _translators.Sort((a, b) => string.Compare(a.ToLowerInvariant(), b.ToLowerInvariant(), StringComparison.Ordinal)); + Translators.Sort((a, b) => string.Compare(a.ToLowerInvariant(), b.ToLowerInvariant(), StringComparison.Ordinal)); } public void Draw(bool changed) @@ -85,10 +85,8 @@ internal sealed class About : ISettingsTab using var translatorChild = ImRaii.Child("translators"); if (translatorChild) { - foreach (var translator in _translators) - { + foreach (var translator in Translators) ImGui.TextUnformatted(translator); - } } } } diff --git a/ChatTwo/Ui/SettingsTabs/Preview.cs b/ChatTwo/Ui/SettingsTabs/Preview.cs index a67d6fd..253db9c 100644 --- a/ChatTwo/Ui/SettingsTabs/Preview.cs +++ b/ChatTwo/Ui/SettingsTabs/Preview.cs @@ -6,14 +6,12 @@ namespace ChatTwo.Ui.SettingsTabs; internal sealed class Preview : ISettingsTab { - private readonly Plugin Plugin; private Configuration Mutable { get; } - public string Name => Language.Options_Preview_Tab + "###tabs-preview"; + public string Name => $"{Language.Options_Preview_Tab}###tabs-preview"; - internal Preview(Plugin plugin, Configuration mutable) + internal Preview(Configuration mutable) { - Plugin = plugin; Mutable = mutable; } diff --git a/ChatTwo/Ui/SettingsTabs/Tabs.cs b/ChatTwo/Ui/SettingsTabs/Tabs.cs index 8c99b34..f8f050d 100755 --- a/ChatTwo/Ui/SettingsTabs/Tabs.cs +++ b/ChatTwo/Ui/SettingsTabs/Tabs.cs @@ -9,16 +9,14 @@ namespace ChatTwo.Ui.SettingsTabs; internal sealed class Tabs : ISettingsTab { - private Plugin Plugin { get; } private Configuration Mutable { get; } public string Name => Language.Options_Tabs_Tab + "###tabs-tabs"; - private int _toOpen = -2; + private int ToOpen = -2; - internal Tabs(Plugin plugin, Configuration mutable) + internal Tabs(Configuration mutable) { - Plugin = plugin; Mutable = mutable; } @@ -47,13 +45,13 @@ internal sealed class Tabs : ISettingsTab } var toRemove = -1; - var doOpens = _toOpen > -2; + var doOpens = ToOpen > -2; for (var i = 0; i < Mutable.Tabs.Count; i++) { var tab = Mutable.Tabs[i]; if (doOpens) - ImGui.SetNextItemOpen(i == _toOpen); + ImGui.SetNextItemOpen(i == ToOpen); using var treeNode = ImRaii.TreeNode($"{tab.Name}###tab-{i}"); if (!treeNode.Success) @@ -64,7 +62,7 @@ internal sealed class Tabs : ISettingsTab if (ImGuiUtil.IconButton(FontAwesomeIcon.TrashAlt, tooltip: Language.Options_Tabs_Delete)) { toRemove = i; - _toOpen = -1; + ToOpen = -1; } ImGui.SameLine(); @@ -72,7 +70,7 @@ internal sealed class Tabs : ISettingsTab if (ImGuiUtil.IconButton(FontAwesomeIcon.ArrowUp, tooltip: Language.Options_Tabs_MoveUp) && i > 0) { (Mutable.Tabs[i - 1], Mutable.Tabs[i]) = (Mutable.Tabs[i], Mutable.Tabs[i - 1]); - _toOpen = i - 1; + ToOpen = i - 1; } ImGui.SameLine(); @@ -80,7 +78,7 @@ internal sealed class Tabs : ISettingsTab if (ImGuiUtil.IconButton(FontAwesomeIcon.ArrowDown, tooltip: Language.Options_Tabs_MoveDown) && i < Mutable.Tabs.Count - 1) { (Mutable.Tabs[i + 1], Mutable.Tabs[i]) = (Mutable.Tabs[i], Mutable.Tabs[i + 1]); - _toOpen = i + 1; + ToOpen = i + 1; } ImGui.InputText(Language.Options_Tabs_Name, ref tab.Name, 512, ImGuiInputTextFlags.EnterReturnsTrue); @@ -135,6 +133,6 @@ internal sealed class Tabs : ISettingsTab Mutable.Tabs.RemoveAt(toRemove); if (doOpens) - _toOpen = -2; + ToOpen = -2; } } diff --git a/ChatTwo/Util/ChunkUtil.cs b/ChatTwo/Util/ChunkUtil.cs index b42b4b0..ededc4a 100755 --- a/ChatTwo/Util/ChunkUtil.cs +++ b/ChatTwo/Util/ChunkUtil.cs @@ -2,6 +2,9 @@ using ChatTwo.Code; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling.Payloads; using System.Text; +using Lumina.Text.Payloads; + +using PayloadType = Dalamud.Game.Text.SeStringHandling.PayloadType; namespace ChatTwo.Util; @@ -112,6 +115,11 @@ internal static class ChunkUtil var id = GetInteger(reader); link = new AchievementPayload(id); } + else if (rawPayload.Data is [_, (byte)MacroCode.NonBreakingSpace, _, _]) + { + // NonBreakingSpace payload + Append(" "); + } // NOTE: no URIPayload because it originates solely from // new Message(). The game doesn't have a URI payload type. else if (Equals(rawPayload, RawPayload.LinkTerminator)) diff --git a/ChatTwo/Util/ExtraPayload.cs b/ChatTwo/Util/ExtraPayload.cs index 27842c1..5430c11 100644 --- a/ChatTwo/Util/ExtraPayload.cs +++ b/ChatTwo/Util/ExtraPayload.cs @@ -1,8 +1,4 @@ -using Dalamud.Utility; -using FFXIVClientStructs.FFXIV.Client.UI.Misc; -using FFXIVClientStructs.FFXIV.Component.Text; - -namespace ChatTwo.Util; +namespace ChatTwo.Util; public class ColorPayload {