feat: handle sig failures better
This commit is contained in:
parent
fbf3afd7a2
commit
f768ef6480
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue