- Handle NBSP payloads
- Use ingame version of axis font
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Version>1.29.8</Version>
|
||||
<Version>1.29.9</Version>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -20,7 +20,6 @@ public class FontManager
|
||||
|
||||
private ushort[] Ranges;
|
||||
private ushort[] JpRange;
|
||||
private readonly ushort[] SymRange = [0xE020, 0xE0DB, 0];
|
||||
|
||||
|
||||
public static readonly HashSet<float> 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;
|
||||
}
|
||||
|
||||
@@ -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<UIModule*, Utf8String*, nint, byte, void> 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);
|
||||
|
||||
|
||||
@@ -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<T>(string name) where T : unmanaged
|
||||
private static T* GetAddon<T>(string name) where T : unmanaged
|
||||
{
|
||||
var addon = RaptureAtkModule.Instance()->RaptureAtkUnitManager.GetAddonByName(name);
|
||||
return addon != null && addon->IsReady ? (T*)addon : null;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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<string, string?>
|
||||
{
|
||||
{ "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<string, string?>
|
||||
{
|
||||
{ "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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,21 +31,21 @@ public sealed class SettingsWindow : Window
|
||||
Plugin = plugin;
|
||||
Mutable = new Configuration();
|
||||
|
||||
Tabs = new List<ISettingsTab>
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -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<string> _translators =
|
||||
private readonly List<string> 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,14 +85,12 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui.Spacing();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user