feat: handle sig failures better

This commit is contained in:
Anna 2021-01-07 16:26:27 -05:00
parent fbf3afd7a2
commit f768ef6480
5 changed files with 234 additions and 164 deletions

View File

@ -33,7 +33,7 @@ namespace XIVChatPlugin {
var colours = new List<Vector4>();
var colour = new Vector4(0f, 0f, 0f, 1f);
for (int i = 0; i < bytes.Length; i++) {
for (var i = 0; i < bytes.Length; i++) {
var idx = i % 3;
if (i != 0 && idx == 0) {

View File

@ -6,13 +6,14 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Dalamud.Plugin;
using XIVChatCommon.Message;
namespace XIVChatPlugin {
public class GameFunctions : IDisposable {
private readonly Plugin plugin;
private Plugin Plugin { get; }
private delegate IntPtr GetUIModuleDelegate(IntPtr basePtr);
private delegate IntPtr GetUiModuleDelegate(IntPtr basePtr);
private delegate void EasierProcessChatBoxDelegate(IntPtr uiModule, IntPtr message, IntPtr unused, byte a4);
@ -24,58 +25,113 @@ namespace XIVChatPlugin {
private delegate IntPtr GetColourInfoDelegate(IntPtr handler, uint lookupResult);
private readonly Hook<RequestFriendListDelegate> friendListHook;
private readonly Hook<FormatFriendListNameDelegate> formatHook;
private readonly Hook<OnReceiveFriendListChunkDelegate> receiveChunkHook;
private delegate byte ChatChannelChangeDelegate(IntPtr a1, uint channel);
private readonly GetUIModuleDelegate getUiModule;
private readonly EasierProcessChatBoxDelegate easierProcessChatBox;
private readonly GetColourInfoDelegate getColourInfo;
private readonly Hook<RequestFriendListDelegate>? _friendListHook;
private readonly Hook<FormatFriendListNameDelegate>? _formatHook;
private readonly Hook<OnReceiveFriendListChunkDelegate>? _receiveChunkHook;
private readonly Hook<ChatChannelChangeDelegate>? _chatChannelChangeHook;
private readonly IntPtr uiModulePtr;
private readonly IntPtr colourHandler;
private readonly IntPtr colourLookup;
private IntPtr friendListManager = IntPtr.Zero;
private readonly GetUiModuleDelegate? _getUiModule;
private readonly EasierProcessChatBoxDelegate? _easierProcessChatBox;
private readonly GetColourInfoDelegate? _getColourInfo;
private IntPtr UiModulePtr { get; }
private IntPtr ColourHandler { get; }
private IntPtr ColourLookup { get; }
private IntPtr _friendListManager = IntPtr.Zero;
public bool RequestingFriendList { get; private set; }
private readonly List<Player> friends = new List<Player>();
private readonly List<Player> _friends = new List<Player>();
public delegate void ReceiveFriendListHandler(List<Player> friends);
public event ReceiveFriendListHandler? ReceiveFriendList;
public GameFunctions(Plugin plugin) {
this.plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "Plugin cannot be null");
this.Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "Plugin cannot be null");
var getUiModulePtr = this.plugin.Interface.TargetModuleScanner.ScanText("E8 ?? ?? ?? ?? 48 83 7F ?? 00 48 8B F0");
var easierProcessChatBoxPtr = this.plugin.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 45 84 C9");
var friendListPtr = this.plugin.Interface.TargetModuleScanner.ScanText("40 53 48 81 EC 80 0F 00 00 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B D9 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 C0 0F 84 ?? ?? ?? ?? 44 0F B6 43 ?? 33 C9");
var formatPtr = this.plugin.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 41 56 48 83 EC 30 48 8B 6C 24 ??");
var recvChunkPtr = this.plugin.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 56 48 83 EC 20 48 8B 0D ?? ?? ?? ?? 48 8B F2");
var getColourPtr = this.plugin.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 8B F2 48 8D B9 ?? ?? ?? ??");
var getUiModulePtr = this.Plugin.ScanText("E8 ?? ?? ?? ?? 48 83 7F ?? 00 48 8B F0");
var easierProcessChatBoxPtr = this.Plugin.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 45 84 C9");
var friendListPtr = this.Plugin.ScanText("40 53 48 81 EC 80 0F 00 00 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B D9 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 C0 0F 84 ?? ?? ?? ?? 44 0F B6 43 ?? 33 C9");
var formatPtr = this.Plugin.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 41 56 48 83 EC 30 48 8B 6C 24 ??");
var recvChunkPtr = this.Plugin.ScanText("48 89 5C 24 ?? 56 48 83 EC 20 48 8B 0D ?? ?? ?? ?? 48 8B F2");
var getColourPtr = this.Plugin.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 8B F2 48 8D B9 ?? ?? ?? ??");
var channelPtr = this.Plugin.ScanText("40 55 48 8D 6C 24 ?? 48 81 EC A0 00 00 00 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 45 ?? 48 8B 0D ?? ?? ?? ?? 33 C0 48 83 C1 10 89 45 ?? C7 45 ?? 01 00 00 00");
this.uiModulePtr = this.plugin.Interface.TargetModuleScanner.GetStaticAddressFromSig("48 8B 0D ?? ?? ?? ?? 48 8D 54 24 ?? 48 83 C1 10 E8 ?? ?? ?? ??");
this.colourHandler = this.plugin.Interface.TargetModuleScanner.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 8B A8 ?? ?? ?? ?? 48 85 ED 0F 84 ?? ?? ?? ??");
this.colourLookup = this.plugin.Interface.TargetModuleScanner.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? 8B 14 ?? 85 D2 7E ?? 48 8B 0D ?? ?? ?? ?? 48 83 C1 10 E8 ?? ?? ?? ?? 8B 70 ?? 41 8D 4D ??");
this.UiModulePtr = this.Plugin.GetStaticAddressFromSig("48 8B 0D ?? ?? ?? ?? 48 8D 54 24 ?? 48 83 C1 10 E8 ?? ?? ?? ??");
this.getUiModule = Marshal.GetDelegateForFunctionPointer<GetUIModuleDelegate>(getUiModulePtr);
this.easierProcessChatBox = Marshal.GetDelegateForFunctionPointer<EasierProcessChatBoxDelegate>(easierProcessChatBoxPtr);
this.getColourInfo = Marshal.GetDelegateForFunctionPointer<GetColourInfoDelegate>(getColourPtr);
if (this.UiModulePtr == IntPtr.Zero) {
PluginLog.Warning("Static pointer was null: {}", nameof(this.UiModulePtr));
}
this.friendListHook = new Hook<RequestFriendListDelegate>(friendListPtr, new RequestFriendListDelegate(this.OnRequestFriendList));
this.formatHook = new Hook<FormatFriendListNameDelegate>(formatPtr, new FormatFriendListNameDelegate(this.OnFormatFriendList));
this.receiveChunkHook = new Hook<OnReceiveFriendListChunkDelegate>(recvChunkPtr, new OnReceiveFriendListChunkDelegate(this.OnReceiveFriendList));
this.ColourHandler = this.Plugin.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 8B A8 ?? ?? ?? ?? 48 85 ED 0F 84 ?? ?? ?? ??");
if (this.ColourHandler == IntPtr.Zero) {
PluginLog.Warning("Static pointer was null: {}", nameof(this.ColourHandler));
}
this.friendListHook.Enable();
this.formatHook.Enable();
this.receiveChunkHook.Enable();
this.ColourLookup = this.Plugin.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? 8B 14 ?? 85 D2 7E ?? 48 8B 0D ?? ?? ?? ?? 48 83 C1 10 E8 ?? ?? ?? ?? 8B 70 ?? 41 8D 4D ??");
if (this.ColourLookup == IntPtr.Zero) {
PluginLog.Warning("Static pointer was null: {}", nameof(this.ColourLookup));
}
if (getUiModulePtr != IntPtr.Zero) {
this._getUiModule = Marshal.GetDelegateForFunctionPointer<GetUiModuleDelegate>(getUiModulePtr);
} else {
PluginLog.Warning("Pointer was null, disabling function: {}", nameof(getUiModulePtr));
}
if (easierProcessChatBoxPtr != IntPtr.Zero) {
this._easierProcessChatBox = Marshal.GetDelegateForFunctionPointer<EasierProcessChatBoxDelegate>(easierProcessChatBoxPtr);
} else {
PluginLog.Warning("Pointer was null, disabling function: {}", nameof(easierProcessChatBoxPtr));
}
if (getColourPtr != IntPtr.Zero) {
this._getColourInfo = Marshal.GetDelegateForFunctionPointer<GetColourInfoDelegate>(getColourPtr);
} else {
PluginLog.Warning("Pointer was null, disabling function: {}", nameof(getColourPtr));
}
if (friendListPtr != IntPtr.Zero) {
this._friendListHook = new Hook<RequestFriendListDelegate>(friendListPtr, new RequestFriendListDelegate(this.OnRequestFriendList));
} else {
PluginLog.Warning("Pointer was null, disabling hook: {}", nameof(friendListPtr));
}
if (formatPtr != IntPtr.Zero) {
this._formatHook = new Hook<FormatFriendListNameDelegate>(formatPtr, new FormatFriendListNameDelegate(this.OnFormatFriendList));
} else {
PluginLog.Warning("Pointer was null, disabling hook: {}", nameof(formatPtr));
}
if (recvChunkPtr != IntPtr.Zero) {
this._receiveChunkHook = new Hook<OnReceiveFriendListChunkDelegate>(recvChunkPtr, new OnReceiveFriendListChunkDelegate(this.OnReceiveFriendList));
} else {
PluginLog.Warning("Pointer was null, disabling hook: {}", nameof(recvChunkPtr));
}
if (channelPtr != IntPtr.Zero) {
this._chatChannelChangeHook = new Hook<ChatChannelChangeDelegate>(channelPtr, new ChatChannelChangeDelegate(this.ChangeChatChannelDetour));
} else {
PluginLog.Warning("Pointer was null, disabling hook: {}", nameof(channelPtr));
}
this._friendListHook?.Enable();
this._formatHook?.Enable();
this._receiveChunkHook?.Enable();
this._chatChannelChangeHook?.Enable();
}
// This function looks up a channel's user-defined colour.
//
// If this function would ever return 0, it returns null instead.
public uint? GetChannelColour(ChatCode channel) {
if (this.ColourLookup == IntPtr.Zero || this.ColourHandler == IntPtr.Zero) {
return null;
}
// Colours are retrieved by looking up their code in a lookup table. Some codes share a colour, so they're lumped into a parent code here.
// Only codes >= 10 (say) have configurable colours.
// After getting the lookup value for the code, it is passed into a function with a handler which returns a pointer.
@ -90,9 +146,9 @@ namespace XIVChatPlugin {
return channel.DefaultColour();
}
var lookupResult = (uint)Marshal.ReadInt32(this.colourLookup, (int)parent * 4);
var info = this.getColourInfo(Marshal.ReadIntPtr(this.colourHandler) + 16, lookupResult);
var rgb = (uint)Marshal.ReadInt32(info, 32) & 0xFFFFFF;
var lookupResult = (uint) Marshal.ReadInt32(this.ColourLookup, (int) parent * 4);
var info = this._getColourInfo(Marshal.ReadIntPtr(this.ColourHandler) + 16, lookupResult);
var rgb = (uint) Marshal.ReadInt32(info, 32) & 0xFFFFFF;
if (rgb == 0) {
return null;
@ -102,39 +158,51 @@ namespace XIVChatPlugin {
}
public void ProcessChatBox(string message) {
IntPtr uiModule = this.getUiModule(Marshal.ReadIntPtr(this.uiModulePtr));
if (this._easierProcessChatBox == null || this.UiModulePtr == IntPtr.Zero) {
return;
}
var uiModule = this._getUiModule(Marshal.ReadIntPtr(this.UiModulePtr));
if (uiModule == IntPtr.Zero) {
throw new ApplicationException("uiModule was null");
throw new ArgumentException("pointer was null", nameof(uiModule));
}
using var payload = new ChatPayload(message);
IntPtr mem1 = Marshal.AllocHGlobal(400);
var mem1 = Marshal.AllocHGlobal(400);
Marshal.StructureToPtr(payload, mem1, false);
this.easierProcessChatBox(uiModule, mem1, IntPtr.Zero, 0);
this._easierProcessChatBox(uiModule, mem1, IntPtr.Zero, 0);
Marshal.FreeHGlobal(mem1);
}
public bool RequestFriendList() {
if (this.friendListManager == IntPtr.Zero) {
if (this._friendListManager == IntPtr.Zero || this._friendListHook == null) {
return false;
}
this.RequestingFriendList = true;
this.friendListHook.Original(this.friendListManager);
this._friendListHook.Original(this._friendListManager);
return true;
}
private byte ChangeChatChannelDetour(IntPtr a1, uint channel) {
// a1 + 0xfd0 is the chat channel byte (including for when clicking on shout)
this.Plugin.Server.OnChatChannelChange(channel);
return this._chatChannelChangeHook!.Original(a1, channel);
}
private byte OnRequestFriendList(IntPtr manager) {
this.friendListManager = manager;
return this.friendListHook.Original(manager);
this._friendListManager = manager;
// NOTE: if this is being called, hook isn't null
return this._friendListHook!.Original(manager);
}
private int OnFormatFriendList(long a1, long a2, long a3, int a4, IntPtr data, long a6) {
// have to call this first to populate cross-world info
var ret = this.formatHook.Original(a1, a2, a3, a4, data, a6);
// NOTE: if this is being called, hook isn't null
var ret = this._formatHook!.Original(a1, a2, a3, a4, data, a6);
if (!this.RequestingFriendList) {
return ret;
@ -144,13 +212,13 @@ namespace XIVChatPlugin {
string? jobName = null;
if (entry.job > 0) {
jobName = this.plugin.Interface.Data.GetExcelSheet<ClassJob>().GetRow(entry.job)?.Name;
jobName = this.Plugin.Interface.Data.GetExcelSheet<ClassJob>().GetRow(entry.job)?.Name;
}
// FIXME: remove this try/catch when lumina fixes bug with .Value
string? territoryName;
try {
territoryName = this.plugin.Interface.Data.GetExcelSheet<TerritoryType>().GetRow(entry.territoryId)?.PlaceName?.Value?.Name;
territoryName = this.Plugin.Interface.Data.GetExcelSheet<TerritoryType>().GetRow(entry.territoryId)?.PlaceName?.Value?.Name;
} catch (NullReferenceException) {
territoryName = null;
}
@ -161,9 +229,9 @@ namespace XIVChatPlugin {
Status = entry.flags,
CurrentWorld = entry.currentWorldId,
CurrentWorldName = this.plugin.Interface.Data.GetExcelSheet<World>().GetRow(entry.currentWorldId)?.Name,
CurrentWorldName = this.Plugin.Interface.Data.GetExcelSheet<World>().GetRow(entry.currentWorldId)?.Name,
HomeWorld = entry.homeWorldId,
HomeWorldName = this.plugin.Interface.Data.GetExcelSheet<World>().GetRow(entry.homeWorldId)?.Name,
HomeWorldName = this.Plugin.Interface.Data.GetExcelSheet<World>().GetRow(entry.homeWorldId)?.Name,
Territory = entry.territoryId,
TerritoryName = territoryName,
@ -172,18 +240,19 @@ namespace XIVChatPlugin {
JobName = jobName,
GrandCompany = entry.grandCompany,
GrandCompanyName = this.plugin.Interface.Data.GetExcelSheet<GrandCompany>().GetRow(entry.grandCompany)?.Name,
GrandCompanyName = this.Plugin.Interface.Data.GetExcelSheet<GrandCompany>().GetRow(entry.grandCompany)?.Name,
Languages = entry.langsEnabled,
MainLanguage = entry.mainLanguage,
};
this.friends.Add(player);
this._friends.Add(player);
return ret;
}
private IntPtr OnReceiveFriendList(IntPtr a1, IntPtr data) {
var ret = this.receiveChunkHook.Original(a1, data);
// NOTE: if this is being called, hook isn't null
var ret = this._receiveChunkHook!.Original(a1, data);
// + 0xc
// 1 = party
@ -201,8 +270,8 @@ namespace XIVChatPlugin {
goto Return;
}
this.ReceiveFriendList?.Invoke(this.friends);
this.friends.Clear();
this.ReceiveFriendList?.Invoke(this._friends);
this._friends.Clear();
this.RequestingFriendList = false;
Return:
@ -210,9 +279,10 @@ namespace XIVChatPlugin {
}
public void Dispose() {
this.friendListHook.Dispose();
this.formatHook.Dispose();
this.receiveChunkHook.Dispose();
this._friendListHook?.Dispose();
this._formatHook?.Dispose();
this._receiveChunkHook?.Dispose();
this._chatChannelChangeHook?.Dispose();
}
}
@ -237,7 +307,7 @@ namespace XIVChatPlugin {
Marshal.Copy(stringBytes, 0, this.textPtr, stringBytes.Length);
Marshal.WriteByte(this.textPtr + stringBytes.Length, 0);
this.textLen = (ulong)(stringBytes.Length + 1);
this.textLen = (ulong) (stringBytes.Length + 1);
this.unk1 = 64;
this.unk2 = 0;

View File

@ -13,7 +13,7 @@ using System.Reflection;
namespace XIVChatPlugin {
public class Plugin : IDalamudPlugin {
private bool disposedValue;
private bool _disposedValue;
public string Name => "XIVChat";
@ -28,15 +28,11 @@ namespace XIVChatPlugin {
#pragma warning disable 8618
public DalamudPluginInterface Interface { get; private set; }
public Configuration Config { get; private set; }
private PluginUI Ui { get; set; }
private PluginUi Ui { get; set; }
public Server Server { get; private set; }
public GameFunctions Functions { get; private set; }
#pragma warning restore 8618
private delegate byte ChatChannelChangeDelegate(IntPtr a1, uint channel);
private Hook<ChatChannelChangeDelegate>? chatChannelChangeHook;
public void Initialize(DalamudPluginInterface pluginInterface) {
this.Interface = pluginInterface ?? throw new ArgumentNullException(nameof(pluginInterface), "DalamudPluginInterface cannot be null");
@ -51,15 +47,8 @@ namespace XIVChatPlugin {
this.Config.Initialise(this);
this.Functions = new GameFunctions(this);
try {
var funcPtr = this.Interface.TargetModuleScanner.ScanText("40 55 48 8D 6C 24 ?? 48 81 EC A0 00 00 00 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 45 ?? 48 8B 0D ?? ?? ?? ?? 33 C0 48 83 C1 10 89 45 ?? C7 45 ?? 01 00 00 00");
this.chatChannelChangeHook = new Hook<ChatChannelChangeDelegate>(funcPtr, new ChatChannelChangeDelegate(this.ChangeChatChannelDetour));
this.chatChannelChangeHook.Enable();
} catch (KeyNotFoundException) {
PluginLog.LogError("Could not sig chat channel change function");
}
this.Ui = new PluginUI(this);
this.Ui = new PluginUi(this);
this.LaunchServer();
@ -75,7 +64,23 @@ namespace XIVChatPlugin {
});
}
public void LaunchServer() {
internal IntPtr ScanText(string sig) {
try {
return this.Interface.TargetModuleScanner.ScanText(sig);
} catch (KeyNotFoundException) {
return IntPtr.Zero;
}
}
internal IntPtr GetStaticAddressFromSig(string sig) {
try {
return this.Interface.TargetModuleScanner.GetStaticAddressFromSig(sig);
} catch (KeyNotFoundException) {
return IntPtr.Zero;
}
}
private void LaunchServer() {
this.Server = new Server(this);
this.Server.Spawn();
}
@ -85,19 +90,13 @@ namespace XIVChatPlugin {
this.LaunchServer();
}
private byte ChangeChatChannelDetour(IntPtr a1, uint channel) {
// a1 + 0xfd0 is the chat channel byte (including for when clicking on shout)
this.Server.OnChatChannelChange(channel);
return this.chatChannelChangeHook!.Original(a1, channel);
}
private void OnCommand(string command, string args) {
this.Ui.OpenSettings(null, null);
}
[SuppressMessage("ReSharper", "DelegateSubtraction")]
protected virtual void Dispose(bool disposing) {
if (this.disposedValue) {
if (this._disposedValue) {
return;
}
@ -112,11 +111,9 @@ namespace XIVChatPlugin {
this.Interface.ClientState.OnLogout -= this.Server.OnLogOut;
this.Interface.ClientState.TerritoryChanged -= this.Server.OnTerritoryChange;
this.Interface.CommandManager.RemoveHandler("/xivchat");
this.chatChannelChangeHook?.Dispose();
}
this.disposedValue = true;
this._disposedValue = true;
}
public void Dispose() {

View File

@ -7,17 +7,17 @@ using System.Numerics;
using System.Threading.Channels;
namespace XIVChatPlugin {
public class PluginUI {
private readonly Plugin plugin;
public class PluginUi {
private Plugin Plugin { get; }
private bool showSettings;
private bool ShowSettings { get => this.showSettings; set => this.showSettings = value; }
private bool _showSettings;
private bool ShowSettings { get => this._showSettings; set => this._showSettings = value; }
private readonly Dictionary<Guid, Tuple<Client, Channel<bool>>> pending = new Dictionary<Guid, Tuple<Client, Channel<bool>>>();
private readonly Dictionary<Guid, string> pendingNames = new Dictionary<Guid, string>(0);
private readonly Dictionary<Guid, Tuple<Client, Channel<bool>>> _pending = new Dictionary<Guid, Tuple<Client, Channel<bool>>>();
private readonly Dictionary<Guid, string> _pendingNames = new Dictionary<Guid, string>(0);
public PluginUI(Plugin plugin) {
this.plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "Plugin cannot be null");
public PluginUi(Plugin plugin) {
this.Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "Plugin cannot be null");
}
private static class Colours {
@ -47,7 +47,7 @@ namespace XIVChatPlugin {
ImGui.PopStyleColor(8);
}
private static V WithWhiteText<V>(Func<V> func) {
private static T WithWhiteText<T>(Func<T> func) {
ImGui.PushStyleColor(ImGuiCol.Text, Colours.White);
var ret = func();
ImGui.PopStyleColor();
@ -89,58 +89,58 @@ namespace XIVChatPlugin {
private void DrawInner() {
this.AcceptPending();
foreach (var item in this.pending.ToList()) {
foreach (var item in this._pending.ToList()) {
if (this.DrawPending(item.Key, item.Value.Item1, item.Value.Item2)) {
this.pending.Remove(item.Key);
this._pending.Remove(item.Key);
}
}
if (!this.ShowSettings || !Begin(this.plugin.Name, ref this.showSettings, ImGuiWindowFlags.AlwaysAutoResize)) {
if (!this.ShowSettings || !Begin(this.Plugin.Name, ref this._showSettings, ImGuiWindowFlags.AlwaysAutoResize)) {
return;
}
if (WithWhiteText(() => ImGui.CollapsingHeader("Server public key"))) {
string serverPublic = this.plugin.Config.KeyPair!.PublicKey.ToHexString(upper: true);
string serverPublic = this.Plugin.Config.KeyPair!.PublicKey.ToHexString(upper: true);
ImGui.TextUnformatted(serverPublic);
this.DrawColours(this.plugin.Config.KeyPair.PublicKey, serverPublic);
DrawColours(this.Plugin.Config.KeyPair.PublicKey, serverPublic);
if (WithWhiteText(() => ImGui.Button("Regenerate"))) {
this.plugin.Server.RegenerateKeyPair();
this.Plugin.Server.RegenerateKeyPair();
}
}
if (WithWhiteText(() => ImGui.CollapsingHeader("Settings", ImGuiTreeNodeFlags.DefaultOpen))) {
TextWhite("Port");
int port = this.plugin.Config.Port;
int port = this.Plugin.Config.Port;
if (WithWhiteText(() => ImGui.InputInt("##port", ref port))) {
ushort realPort = (ushort)Math.Min(ushort.MaxValue, Math.Max(1, port));
this.plugin.Config.Port = realPort;
this.plugin.Config.Save();
var realPort = (ushort)Math.Min(ushort.MaxValue, Math.Max(1, port));
this.Plugin.Config.Port = realPort;
this.Plugin.Config.Save();
this.plugin.RelaunchServer();
this.Plugin.RelaunchServer();
}
ImGui.Spacing();
bool backlogEnabled = this.plugin.Config.BacklogEnabled;
var backlogEnabled = this.Plugin.Config.BacklogEnabled;
if (WithWhiteText(() => ImGui.Checkbox("Enable backlog", ref backlogEnabled))) {
this.plugin.Config.BacklogEnabled = backlogEnabled;
this.plugin.Config.Save();
this.Plugin.Config.BacklogEnabled = backlogEnabled;
this.Plugin.Config.Save();
}
int backlogCount = this.plugin.Config.BacklogCount;
int backlogCount = this.Plugin.Config.BacklogCount;
if (WithWhiteText(() => ImGui.DragInt("Backlog messages", ref backlogCount, 1f, 0, ushort.MaxValue))) {
this.plugin.Config.BacklogCount = (ushort)Math.Max(0, Math.Min(ushort.MaxValue, backlogCount));
this.plugin.Config.Save();
this.Plugin.Config.BacklogCount = (ushort)Math.Max(0, Math.Min(ushort.MaxValue, backlogCount));
this.Plugin.Config.Save();
}
ImGui.Spacing();
bool sendBattle = this.plugin.Config.SendBattle;
var sendBattle = this.Plugin.Config.SendBattle;
if (WithWhiteText(() => ImGui.Checkbox("Send battle messages", ref sendBattle))) {
this.plugin.Config.SendBattle = sendBattle;
this.plugin.Config.Save();
this.Plugin.Config.SendBattle = sendBattle;
this.Plugin.Config.Save();
}
ImGui.SameLine();
@ -148,10 +148,10 @@ namespace XIVChatPlugin {
ImGui.Spacing();
bool pairingMode = this.plugin.Config.PairingMode;
var pairingMode = this.Plugin.Config.PairingMode;
if (WithWhiteText(() => ImGui.Checkbox("Pairing mode", ref pairingMode))) {
this.plugin.Config.PairingMode = pairingMode;
this.plugin.Config.Save();
this.Plugin.Config.PairingMode = pairingMode;
this.Plugin.Config.Save();
}
ImGui.SameLine();
@ -159,10 +159,10 @@ namespace XIVChatPlugin {
ImGui.Spacing();
bool acceptNew = this.plugin.Config.AcceptNewClients;
var acceptNew = this.Plugin.Config.AcceptNewClients;
if (WithWhiteText(() => ImGui.Checkbox("Accept new clients", ref acceptNew))) {
this.plugin.Config.AcceptNewClients = acceptNew;
this.plugin.Config.Save();
this.Plugin.Config.AcceptNewClients = acceptNew;
this.Plugin.Config.Save();
}
ImGui.SameLine();
@ -170,13 +170,13 @@ namespace XIVChatPlugin {
}
if (WithWhiteText(() => ImGui.CollapsingHeader("Trusted keys"))) {
if (this.plugin.Config.TrustedKeys.Count == 0) {
if (this.Plugin.Config.TrustedKeys.Count == 0) {
ImGui.TextUnformatted("None");
}
ImGui.Columns(2);
var maxKeyLength = 0f;
foreach (var entry in this.plugin.Config.TrustedKeys.ToList()) {
foreach (var entry in this.Plugin.Config.TrustedKeys.ToList()) {
var name = entry.Value.Item1;
var key = entry.Value.Item2;
@ -188,15 +188,15 @@ namespace XIVChatPlugin {
if (ImGui.IsItemHovered()) {
ImGui.BeginTooltip();
ImGui.TextUnformatted(hex);
this.DrawColours(key, hex);
DrawColours(key, hex);
ImGui.EndTooltip();
}
ImGui.NextColumn();
if (WithWhiteText(() => ImGui.Button($"Untrust##{entry.Key}"))) {
this.plugin.Config.TrustedKeys.Remove(entry.Key);
this.plugin.Config.Save();
this.Plugin.Config.TrustedKeys.Remove(entry.Key);
this.Plugin.Config.Save();
}
ImGui.NextColumn();
@ -208,7 +208,7 @@ namespace XIVChatPlugin {
if (WithWhiteText(() => ImGui.CollapsingHeader("Connected clients"))) {
if (this.plugin.Server.Clients.Count == 0) {
if (this.Plugin.Server.Clients.Count == 0) {
ImGui.TextUnformatted("None");
} else {
ImGui.Columns(3);
@ -219,7 +219,7 @@ namespace XIVChatPlugin {
ImGui.NextColumn();
ImGui.NextColumn();
foreach (var client in this.plugin.Server.Clients) {
foreach (var client in this.Plugin.Server.Clients) {
EndPoint remote;
try {
remote = client.Value.Conn.Client.RemoteEndPoint;
@ -238,7 +238,7 @@ namespace XIVChatPlugin {
ImGui.NextColumn();
var trustedKey = this.plugin.Config.TrustedKeys.Values.FirstOrDefault(entry => entry.Item2.SequenceEqual(client.Value.Handshake!.RemotePublicKey));
var trustedKey = this.Plugin.Config.TrustedKeys.Values.FirstOrDefault(entry => entry.Item2.SequenceEqual(client.Value.Handshake!.RemotePublicKey));
if (trustedKey != null && !trustedKey.Equals(default(Tuple<string, byte[]>))) {
ImGui.TextUnformatted(trustedKey!.Item1);
if (ImGui.IsItemHovered()) {
@ -246,7 +246,7 @@ namespace XIVChatPlugin {
var hex = trustedKey.Item2.ToHexString(true);
ImGui.TextUnformatted(hex);
this.DrawColours(trustedKey.Item2, hex);
DrawColours(trustedKey.Item2, hex);
ImGui.EndTooltip();
}
@ -278,19 +278,19 @@ namespace XIVChatPlugin {
ImGui.End();
}
private void DrawColours(byte[] bytes, string widthOf) {
this.DrawColours(bytes, ImGui.CalcTextSize(widthOf).X);
private static void DrawColours(byte[] bytes, string widthOf) {
DrawColours(bytes, ImGui.CalcTextSize(widthOf).X);
}
private void DrawColours(byte[] bytes, float width = 0f) {
private static void DrawColours(byte[] bytes, float width = 0f) {
var pos = ImGui.GetCursorScreenPos();
var spacing = ImGui.GetStyle().ItemSpacing;
var colours = bytes.ToColours();
float sizeX = width == 0f ? 32f : width / colours.Count;
var sizeX = width == 0f ? 32f : width / colours.Count;
for (int i = 0; i < colours.Count; i++) {
for (var i = 0; i < colours.Count; i++) {
var topLeft = new Vector2(
pos.X + (sizeX * i),
pos.Y + spacing.Y
@ -316,17 +316,17 @@ namespace XIVChatPlugin {
}
private void AcceptPending() {
while (this.plugin.Server.pendingClients.Reader.TryRead(out var item)) {
this.pending[Guid.NewGuid()] = item;
while (this.Plugin.Server.pendingClients.Reader.TryRead(out var item)) {
this._pending[Guid.NewGuid()] = item;
}
}
private bool DrawPending(Guid id, Client client, Channel<bool, bool> accepted) {
bool ret = false;
var ret = false;
var clientPublic = client.Handshake!.RemotePublicKey;
var clientPublicHex = clientPublic.ToHexString(upper: true);
var serverPublic = this.plugin.Config.KeyPair!.PublicKey;
var serverPublic = this.Plugin.Config.KeyPair!.PublicKey;
var serverPublicHex = serverPublic.ToHexString(upper: true);
var width = Math.Max(ImGui.CalcTextSize(clientPublicHex).X, ImGui.CalcTextSize(serverPublicHex).X) + (ImGui.GetStyle().WindowPadding.X * 2);
@ -343,13 +343,13 @@ namespace XIVChatPlugin {
TextWhite("Server");
ImGui.TextUnformatted(serverPublicHex);
this.DrawColours(serverPublic, serverPublicHex);
DrawColours(serverPublic, serverPublicHex);
ImGui.Spacing();
TextWhite("Client");
ImGui.TextUnformatted(clientPublicHex);
this.DrawColours(clientPublic, clientPublicHex);
DrawColours(clientPublic, clientPublicHex);
ImGui.Separator();
@ -357,12 +357,12 @@ namespace XIVChatPlugin {
ImGui.PopTextWrapPos();
if (!this.pendingNames.TryGetValue(id, out string name)) {
if (!this._pendingNames.TryGetValue(id, out string name)) {
name = "No name";
}
if (WithWhiteText(() => ImGui.InputText("Client name", ref name, 100, ImGuiInputTextFlags.AutoSelectAll))) {
this.pendingNames[id] = name;
this._pendingNames[id] = name;
}
ImGui.Separator();
@ -370,16 +370,16 @@ namespace XIVChatPlugin {
ImGui.TextUnformatted("Do both keys match?");
if (WithWhiteText(() => ImGui.Button("Yes"))) {
accepted.Writer.TryWrite(true);
this.plugin.Config.TrustedKeys[Guid.NewGuid()] = Tuple.Create(name, client.Handshake.RemotePublicKey);
this.plugin.Config.Save();
this.pendingNames.Remove(id);
this.Plugin.Config.TrustedKeys[Guid.NewGuid()] = Tuple.Create(name, client.Handshake.RemotePublicKey);
this.Plugin.Config.Save();
this._pendingNames.Remove(id);
ret = true;
}
ImGui.SameLine();
if (WithWhiteText(() => ImGui.Button("No"))) {
accepted.Writer.TryWrite(false);
this.pendingNames.Remove(id);
this._pendingNames.Remove(id);
ret = true;
}

View File

@ -120,7 +120,7 @@ namespace XIVChatPlugin {
// magic + string length + string + port + key
var payload = new byte[1 + 1 + utf8.Length + portBytes.Length + key.Length]; // assuming names can only be 32 bytes here
payload[0] = 14;
payload[1] = (byte)utf8.Length;
payload[1] = (byte) utf8.Length;
Array.Copy(utf8, 0, payload, 2, utf8.Length);
Array.Copy(portBytes, 0, payload, 2 + utf8.Length, portBytes.Length);
Array.Copy(key, 0, payload, 2 + utf8.Length + portBytes.Length, key.Length);
@ -180,7 +180,7 @@ namespace XIVChatPlugin {
return;
}
var chatCode = new ChatCode((ushort)type);
var chatCode = new ChatCode((ushort) type);
if (!this.plugin.Config.SendBattle && chatCode.IsBattle()) {
return;
@ -207,7 +207,7 @@ namespace XIVChatPlugin {
var msg = new ServerMessage(
DateTime.UtcNow,
(ChatType)type,
(ChatType) type,
sender.Encode(),
message.Encode(),
chunks
@ -340,7 +340,7 @@ namespace XIVChatPlugin {
continue;
}
var op = (ClientOperation)msg[0];
var op = (ClientOperation) msg[0];
var payload = new byte[msg.Length - 1];
Array.Copy(msg, 1, payload, 0, payload.Length);
@ -430,7 +430,8 @@ namespace XIVChatPlugin {
try {
conn.Close();
} catch (ObjectDisposedException) { }
} catch (ObjectDisposedException) {
}
await listen;
@ -439,7 +440,8 @@ namespace XIVChatPlugin {
}).ContinueWith(_ => {
try {
conn.Close();
} catch (ObjectDisposedException) { }
} catch (ObjectDisposedException) {
}
});
}
@ -469,7 +471,7 @@ namespace XIVChatPlugin {
return cached;
}
var logKind = this.plugin.Interface.Data.GetExcelSheet<LogKind>().GetRow((ushort)type);
var logKind = this.plugin.Interface.Data.GetExcelSheet<LogKind>().GetRow((ushort) type);
if (logKind == null) {
return null;
@ -555,8 +557,8 @@ namespace XIVChatPlugin {
void Append(string text) {
chunks.Add(new TextChunk(text) {
FallbackColour = defaultColour,
Foreground = foreground.Count > 0 ? foreground.Peek() : (uint?)null,
Glow = glow.Count > 0 ? glow.Peek() : (uint?)null,
Foreground = foreground.Count > 0 ? foreground.Peek() : (uint?) null,
Glow = glow.Count > 0 ? glow.Peek() : (uint?) null,
Italic = italic,
});
}
@ -564,11 +566,11 @@ namespace XIVChatPlugin {
foreach (var payload in msg.Payloads) {
switch (payload.Type) {
case PayloadType.EmphasisItalic:
var newStatus = ((EmphasisItalicPayload)payload).IsEnabled;
var newStatus = ((EmphasisItalicPayload) payload).IsEnabled;
italic = newStatus;
break;
case PayloadType.UIForeground:
var foregroundPayload = (UIForegroundPayload)payload;
var foregroundPayload = (UIForegroundPayload) payload;
if (foregroundPayload.IsEnabled) {
foreground.Push(foregroundPayload.UIColor.UIForeground);
} else if (foreground.Count > 0) {
@ -577,7 +579,7 @@ namespace XIVChatPlugin {
break;
case PayloadType.UIGlow:
var glowPayload = (UIGlowPayload)payload;
var glowPayload = (UIGlowPayload) payload;
if (glowPayload.IsEnabled) {
glow.Push(glowPayload.UIColor.UIGlow);
} else if (glow.Count > 0) {
@ -589,20 +591,20 @@ namespace XIVChatPlugin {
chunks.Add(new IconChunk {
index = 54,
});
var autoText = ((AutoTranslatePayload)payload).Text;
var autoText = ((AutoTranslatePayload) payload).Text;
Append(autoText.Substring(2, autoText.Length - 4));
chunks.Add(new IconChunk {
index = 55,
});
break;
case PayloadType.Icon:
var index = ((IconPayload)payload).IconIndex;
var index = ((IconPayload) payload).Icon;
chunks.Add(new IconChunk {
index = (byte)index,
index = (byte) index,
});
break;
case PayloadType.Unknown:
var rawPayload = (RawPayload)payload;
var rawPayload = (RawPayload) payload;
if (rawPayload.Data[1] == 0x13) {
foreground.Pop();
glow.Pop();
@ -647,8 +649,8 @@ namespace XIVChatPlugin {
foreach (var word in input.Split(' ')) {
if (word.Length > limit) {
int wordParts = (int)Math.Ceiling((float)word.Length / limit);
for (int i = 0; i < wordParts; i++) {
var wordParts = (int) Math.Ceiling((float) word.Length / limit);
for (var i = 0; i < wordParts; i++) {
var start = i == 0 ? 0 : (i * limit);
var partLength = limit;
if (prefix.Length != 0) {
@ -738,7 +740,7 @@ namespace XIVChatPlugin {
}
public void OnChatChannelChange(uint channel) {
var inputChannel = (InputChannel)channel;
var inputChannel = (InputChannel) channel;
this.currentChannel = inputChannel;
var localisedName = this.LocalisedChannelName(inputChannel);
@ -810,7 +812,8 @@ namespace XIVChatPlugin {
// time out after 5 seconds
client.Conn.SendTimeout = 5_000;
await SecretMessage.SendSecretMessage(client.Conn.GetStream(), client.Handshake.Keys.tx, ServerShutdown.Instance);
} catch (Exception) { }
} catch (Exception) {
}
}
// cancel threads for open clients