feat(plugin): add PeepingTom integration
This commit is contained in:
parent
a3fcd576a7
commit
c48a3ef0d8
|
@ -13,20 +13,20 @@ using XIVChatCommon.Message.Client;
|
||||||
using XIVChatCommon.Message.Relay;
|
using XIVChatCommon.Message.Relay;
|
||||||
|
|
||||||
namespace XIVChatPlugin {
|
namespace XIVChatPlugin {
|
||||||
public abstract class BaseClient : Stream {
|
internal abstract class BaseClient : Stream {
|
||||||
public virtual bool Connected { get; set; }
|
internal virtual bool Connected { get; set; }
|
||||||
|
|
||||||
public HandshakeInfo? Handshake { get; set; }
|
internal HandshakeInfo? Handshake { get; set; }
|
||||||
|
|
||||||
public ClientPreferences? Preferences { get; set; }
|
internal ClientPreferences? Preferences { get; set; }
|
||||||
|
|
||||||
public IPAddress? Remote { get; set; }
|
internal IPAddress? Remote { get; set; }
|
||||||
|
|
||||||
public CancellationTokenSource TokenSource { get; } = new();
|
internal CancellationTokenSource TokenSource { get; } = new();
|
||||||
|
|
||||||
public Channel<Encodable> Queue { get; } = Channel.CreateUnbounded<Encodable>();
|
internal Channel<Encodable> Queue { get; } = Channel.CreateUnbounded<Encodable>();
|
||||||
|
|
||||||
public void Disconnect() {
|
internal void Disconnect() {
|
||||||
this.Connected = false;
|
this.Connected = false;
|
||||||
this.TokenSource.Cancel();
|
this.TokenSource.Cancel();
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ namespace XIVChatPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public T? GetPreference<T>(ClientPreference pref, T? def = default) {
|
internal T? GetPreference<T>(ClientPreference pref, T? def = default) {
|
||||||
var prefs = this.Preferences;
|
var prefs = this.Preferences;
|
||||||
|
|
||||||
if (prefs == null) {
|
if (prefs == null) {
|
||||||
|
@ -48,12 +48,12 @@ namespace XIVChatPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class TcpConnected : BaseClient {
|
internal sealed class TcpConnected : BaseClient {
|
||||||
private TcpClient Client { get; }
|
private TcpClient Client { get; }
|
||||||
private readonly Stream _streamImplementation;
|
private readonly Stream _streamImplementation;
|
||||||
private bool _connected;
|
private bool _connected;
|
||||||
|
|
||||||
public override bool Connected {
|
internal override bool Connected {
|
||||||
get {
|
get {
|
||||||
var ret = this._connected;
|
var ret = this._connected;
|
||||||
try {
|
try {
|
||||||
|
@ -67,7 +67,7 @@ namespace XIVChatPlugin {
|
||||||
set => this._connected = value;
|
set => this._connected = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TcpConnected(TcpClient client) {
|
internal TcpConnected(TcpClient client) {
|
||||||
this.Client = client;
|
this.Client = client;
|
||||||
|
|
||||||
this.Client.ReceiveTimeout = 5_000;
|
this.Client.ReceiveTimeout = 5_000;
|
||||||
|
@ -126,7 +126,7 @@ namespace XIVChatPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class RelayConnected : BaseClient {
|
internal sealed class RelayConnected : BaseClient {
|
||||||
internal byte[] PublicKey { get; }
|
internal byte[] PublicKey { get; }
|
||||||
|
|
||||||
private ChannelWriter<IToRelay> ToRelay { get; }
|
private ChannelWriter<IToRelay> ToRelay { get; }
|
||||||
|
@ -137,7 +137,7 @@ namespace XIVChatPlugin {
|
||||||
private List<byte> ReadBuffer { get; } = new();
|
private List<byte> ReadBuffer { get; } = new();
|
||||||
private List<byte> WriteBuffer { get; } = new();
|
private List<byte> WriteBuffer { get; } = new();
|
||||||
|
|
||||||
public RelayConnected(byte[] publicKey, IPAddress remote, ChannelWriter<IToRelay> toRelay, Channel<byte[]> fromRelay) {
|
internal RelayConnected(byte[] publicKey, IPAddress remote, ChannelWriter<IToRelay> toRelay, Channel<byte[]> fromRelay) {
|
||||||
this.PublicKey = publicKey;
|
this.PublicKey = publicKey;
|
||||||
this.Remote = remote;
|
this.Remote = remote;
|
||||||
this.Connected = true;
|
this.Connected = true;
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace XIVChatPlugin {
|
namespace XIVChatPlugin {
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Configuration : IPluginConfiguration {
|
internal class Configuration : IPluginConfiguration {
|
||||||
private Plugin? _plugin;
|
private Plugin? _plugin;
|
||||||
|
|
||||||
public int Version { get; set; } = 1;
|
public int Version { get; set; } = 1;
|
||||||
|
@ -28,11 +28,11 @@ namespace XIVChatPlugin {
|
||||||
public Dictionary<Guid, Tuple<string, byte[]>> TrustedKeys { get; set; } = new();
|
public Dictionary<Guid, Tuple<string, byte[]>> TrustedKeys { get; set; } = new();
|
||||||
public KeyPair? KeyPair { get; set; }
|
public KeyPair? KeyPair { get; set; }
|
||||||
|
|
||||||
public void Initialise(Plugin plugin) {
|
internal void Initialise(Plugin plugin) {
|
||||||
this._plugin = plugin;
|
this._plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save() {
|
internal void Save() {
|
||||||
this._plugin?.Interface.SavePluginConfig(this);
|
this._plugin?.Interface.SavePluginConfig(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Reflection;
|
||||||
|
using Dalamud.Plugin;
|
||||||
|
|
||||||
|
namespace XIVChatPlugin {
|
||||||
|
// ReSharper disable once ClassNeverInstantiated.Global
|
||||||
|
public class DalamudPlugin : IDalamudPlugin {
|
||||||
|
public string Name => "XIVChat";
|
||||||
|
|
||||||
|
private Plugin? Plugin { get; set; }
|
||||||
|
|
||||||
|
// ReSharper disable once UnusedMember.Global
|
||||||
|
// ReSharper disable once AutoPropertyCanBeMadeGetOnly.Local
|
||||||
|
internal string Location { get; private set; } = Assembly.GetExecutingAssembly().Location;
|
||||||
|
|
||||||
|
public void Initialize(DalamudPluginInterface pluginInterface) {
|
||||||
|
this.Plugin = new Plugin(this, pluginInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
this.Plugin?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||||||
|
private void SetLocation(string path) {
|
||||||
|
this.Location = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ using Dalamud.Plugin;
|
||||||
using XIVChatCommon.Message;
|
using XIVChatCommon.Message;
|
||||||
|
|
||||||
namespace XIVChatPlugin {
|
namespace XIVChatPlugin {
|
||||||
public class GameFunctions : IDisposable {
|
internal class GameFunctions : IDisposable {
|
||||||
private Plugin Plugin { get; }
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
private delegate IntPtr GetUiModuleDelegate(IntPtr basePtr);
|
private delegate IntPtr GetUiModuleDelegate(IntPtr basePtr);
|
||||||
|
@ -66,15 +66,15 @@ namespace XIVChatPlugin {
|
||||||
private IntPtr _chatManager = IntPtr.Zero;
|
private IntPtr _chatManager = IntPtr.Zero;
|
||||||
private readonly IntPtr _emptyXivString = IntPtr.Zero;
|
private readonly IntPtr _emptyXivString = IntPtr.Zero;
|
||||||
|
|
||||||
public bool RequestingFriendList { get; private set; }
|
internal bool RequestingFriendList { get; private set; }
|
||||||
|
|
||||||
private readonly List<Player> _friends = new();
|
private readonly List<Player> _friends = new();
|
||||||
|
|
||||||
public delegate void ReceiveFriendListHandler(List<Player> friends);
|
internal delegate void ReceiveFriendListHandler(List<Player> friends);
|
||||||
|
|
||||||
public event ReceiveFriendListHandler? ReceiveFriendList;
|
internal event ReceiveFriendListHandler? ReceiveFriendList;
|
||||||
|
|
||||||
public GameFunctions(Plugin plugin) {
|
internal GameFunctions(Plugin plugin) {
|
||||||
this.Plugin = plugin;
|
this.Plugin = plugin;
|
||||||
|
|
||||||
var getUiModulePtr = this.Plugin.ScanText("E8 ?? ?? ?? ?? 48 83 7F ?? 00 48 8B F0");
|
var getUiModulePtr = this.Plugin.ScanText("E8 ?? ?? ?? ?? 48 83 7F ?? 00 48 8B F0");
|
||||||
|
@ -208,7 +208,7 @@ namespace XIVChatPlugin {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeChatChannel(InputChannel channel) {
|
internal void ChangeChatChannel(InputChannel channel) {
|
||||||
if (this._chatManager == IntPtr.Zero || this._channelChangeCommand == null || this._emptyXivString == IntPtr.Zero) {
|
if (this._chatManager == IntPtr.Zero || this._channelChangeCommand == null || this._emptyXivString == IntPtr.Zero) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -219,7 +219,7 @@ namespace XIVChatPlugin {
|
||||||
// This function looks up a channel's user-defined colour.
|
// This function looks up a channel's user-defined colour.
|
||||||
//
|
//
|
||||||
// If this function would ever return 0, it returns null instead.
|
// If this function would ever return 0, it returns null instead.
|
||||||
public uint? GetChannelColour(ChatCode channel) {
|
internal uint? GetChannelColour(ChatCode channel) {
|
||||||
if (this.ColourLookup == IntPtr.Zero || this.ColourHandler == IntPtr.Zero) {
|
if (this.ColourLookup == IntPtr.Zero || this.ColourHandler == IntPtr.Zero) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ namespace XIVChatPlugin {
|
||||||
return 0xFF | (rgb << 8);
|
return 0xFF | (rgb << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProcessChatBox(string message) {
|
internal void ProcessChatBox(string message) {
|
||||||
if (this._easierProcessChatBox == null || this.UiModulePtr == IntPtr.Zero) {
|
if (this._easierProcessChatBox == null || this.UiModulePtr == IntPtr.Zero) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -271,7 +271,7 @@ namespace XIVChatPlugin {
|
||||||
Marshal.FreeHGlobal(mem1);
|
Marshal.FreeHGlobal(mem1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RequestFriendList() {
|
internal bool RequestFriendList() {
|
||||||
if (this._friendListManager == IntPtr.Zero || this._friendListHook == null) {
|
if (this._friendListManager == IntPtr.Zero || this._friendListHook == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -452,7 +452,7 @@ namespace XIVChatPlugin {
|
||||||
return nonNull.Length == 0 ? null : Encoding.UTF8.GetString(nonNull);
|
return nonNull.Length == 0 ? null : Encoding.UTF8.GetString(nonNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? Name() => HandleString(this.name);
|
internal string? Name() => HandleString(this.name);
|
||||||
public string? FreeCompany() => HandleString(this.fc);
|
internal string? FreeCompany() => HandleString(this.fc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Linq;
|
||||||
|
using Dalamud.Game.ClientState.Actors.Types;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
using XIVChatCommon.Message;
|
||||||
|
using XIVChatCommon.Message.Client;
|
||||||
|
using XIVChatCommon.Message.Server;
|
||||||
|
|
||||||
|
namespace XIVChatPlugin.Ipc {
|
||||||
|
internal class PeepingTom : IDisposable {
|
||||||
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
|
internal PeepingTom(Plugin plugin) {
|
||||||
|
this.Plugin = plugin;
|
||||||
|
|
||||||
|
#pragma warning disable 618
|
||||||
|
this.Plugin.Interface.Subscribe("PeepingTom", this.ReceiveTargeting);
|
||||||
|
#pragma warning restore 618
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
#pragma warning disable 618
|
||||||
|
this.Plugin.Interface.Unsubscribe("PeepingTom");
|
||||||
|
#pragma warning restore 618
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReceiveTargeting(dynamic obj) {
|
||||||
|
List<ExpandoObject> list = obj.Targeting;
|
||||||
|
var players = list
|
||||||
|
.Select((dynamic player) => (uint) player.ActorId)
|
||||||
|
.Select(targeting => this.Plugin.Interface.ClientState.Actors.FirstOrDefault(actor => actor.ActorId == targeting))
|
||||||
|
.Where(actor => actor is PlayerCharacter)
|
||||||
|
.Cast<PlayerCharacter>()
|
||||||
|
.Select(chara => new Player {
|
||||||
|
Name = chara.Name,
|
||||||
|
FreeCompany = chara.CompanyTag,
|
||||||
|
Status = 0,
|
||||||
|
CurrentWorld = (ushort) chara.CurrentWorld.Id,
|
||||||
|
CurrentWorldName = chara.CurrentWorld.GameData.Name.ToString(),
|
||||||
|
HomeWorld = (ushort) chara.HomeWorld.Id,
|
||||||
|
HomeWorldName = chara.HomeWorld.GameData.Name.ToString(),
|
||||||
|
Territory = this.Plugin.Interface.ClientState.TerritoryType,
|
||||||
|
TerritoryName = this.Plugin.Interface.Data.GetExcelSheet<TerritoryType>().GetRow(this.Plugin.Interface.ClientState.TerritoryType)?.Name,
|
||||||
|
Job = (byte) chara.ClassJob.Id,
|
||||||
|
JobName = chara.ClassJob.GameData.Name.ToString(),
|
||||||
|
GrandCompany = 0,
|
||||||
|
GrandCompanyName = null,
|
||||||
|
Languages = 0,
|
||||||
|
MainLanguage = 0,
|
||||||
|
})
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var client in this.Plugin.Server.Clients.Values) {
|
||||||
|
if (!client.GetPreference(ClientPreference.TargetingListSupport, false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Queue.Writer.TryWrite(new ServerPlayerList(PlayerListType.Targeting, players));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace XIVChatPlugin {
|
namespace XIVChatPlugin {
|
||||||
public static unsafe class NativeTools {
|
internal static unsafe class NativeTools {
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
private readonly struct RawVec {
|
private readonly struct RawVec {
|
||||||
public readonly byte** pointer;
|
public readonly byte** pointer;
|
||||||
|
@ -18,7 +18,7 @@ namespace XIVChatPlugin {
|
||||||
[DllImport("xivchat_native_tools.dll")]
|
[DllImport("xivchat_native_tools.dll")]
|
||||||
private static extern void wrap_free(RawVec* raw);
|
private static extern void wrap_free(RawVec* raw);
|
||||||
|
|
||||||
public static IEnumerable<string> Wrap(string input, uint width) {
|
internal static IEnumerable<string> Wrap(string input, uint width) {
|
||||||
RawVec* raw;
|
RawVec* raw;
|
||||||
fixed (byte* ptr = Encoding.UTF8.GetBytes(input).Terminate()) {
|
fixed (byte* ptr = Encoding.UTF8.GetBytes(input).Terminate()) {
|
||||||
raw = wrap(ptr, width);
|
raw = wrap(ptr, width);
|
||||||
|
|
|
@ -2,42 +2,31 @@
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
using System.IO;
|
using System.IO;
|
||||||
#endif
|
#endif
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace XIVChatPlugin {
|
namespace XIVChatPlugin {
|
||||||
// ReSharper disable once ClassNeverInstantiated.Global
|
internal class Plugin : IDisposable {
|
||||||
public class Plugin : IDalamudPlugin {
|
|
||||||
private bool _disposedValue;
|
private bool _disposedValue;
|
||||||
|
|
||||||
public string Name => "XIVChat";
|
internal DalamudPluginInterface Interface { get; }
|
||||||
|
internal DalamudPlugin DalamudPlugin { get; }
|
||||||
|
internal Configuration Config { get; }
|
||||||
|
private PluginUi Ui { get; }
|
||||||
|
internal Server Server { get; private set; } = null!;
|
||||||
|
internal Relay? Relay { get; private set; }
|
||||||
|
internal GameFunctions Functions { get; }
|
||||||
|
private List<IDisposable> Ipcs { get; } = new();
|
||||||
|
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
internal Plugin(DalamudPlugin dalamudPlugin, DalamudPluginInterface pluginInterface) {
|
||||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
this.Interface = pluginInterface;
|
||||||
internal string Location { get; private set; } = Assembly.GetExecutingAssembly().Location;
|
this.DalamudPlugin = dalamudPlugin;
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
|
||||||
private void SetLocation(string path) {
|
|
||||||
this.Location = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DalamudPluginInterface Interface { get; private set; } = null!;
|
|
||||||
public Configuration Config { get; private set; } = null!;
|
|
||||||
private PluginUi Ui { get; set; } = null!;
|
|
||||||
public Server Server { get; private set; } = null!;
|
|
||||||
public Relay? Relay { get; private set; }
|
|
||||||
public GameFunctions Functions { get; private set; } = null!;
|
|
||||||
|
|
||||||
public void Initialize(DalamudPluginInterface pluginInterface) {
|
|
||||||
this.Interface = pluginInterface ?? throw new ArgumentNullException(nameof(pluginInterface), "DalamudPluginInterface cannot be null");
|
|
||||||
|
|
||||||
// load libsodium.so from debug location if in debug mode
|
// load libsodium.so from debug location if in debug mode
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
string path = Environment.GetEnvironmentVariable("PATH")!;
|
string path = Environment.GetEnvironmentVariable("PATH")!;
|
||||||
string newPath = Path.GetDirectoryName(this.Location)!;
|
string newPath = Path.GetDirectoryName(this.DalamudPlugin.Location)!;
|
||||||
Environment.SetEnvironmentVariable("PATH", $"{path};{newPath}");
|
Environment.SetEnvironmentVariable("PATH", $"{path};{newPath}");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -64,6 +53,32 @@ namespace XIVChatPlugin {
|
||||||
this.Interface.CommandManager.AddHandler("/xivchat", new CommandInfo(this.OnCommand) {
|
this.Interface.CommandManager.AddHandler("/xivchat", new CommandInfo(this.OnCommand) {
|
||||||
HelpMessage = "Opens the config for the XIVChat plugin",
|
HelpMessage = "Opens the config for the XIVChat plugin",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.Ipcs.Add(new Ipc.PeepingTom(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
if (this._disposedValue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._disposedValue = true;
|
||||||
|
|
||||||
|
this.Relay?.Dispose();
|
||||||
|
this.Server.Dispose();
|
||||||
|
|
||||||
|
this.Interface.UiBuilder.OnBuildUi -= this.Ui.Draw;
|
||||||
|
this.Interface.UiBuilder.OnOpenConfigUi -= this.Ui.OpenSettings;
|
||||||
|
this.Interface.Framework.OnUpdateEvent -= this.Server.OnFrameworkUpdate;
|
||||||
|
this.Interface.Framework.Gui.Chat.OnChatMessage -= this.Server.OnChat;
|
||||||
|
this.Interface.ClientState.OnLogin -= this.Server.OnLogIn;
|
||||||
|
this.Interface.ClientState.OnLogout -= this.Server.OnLogOut;
|
||||||
|
this.Interface.ClientState.TerritoryChanged -= this.Server.OnTerritoryChange;
|
||||||
|
this.Interface.CommandManager.RemoveHandler("/xivchat");
|
||||||
|
|
||||||
|
foreach (var ipc in this.Ipcs) {
|
||||||
|
ipc.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void StartRelay() {
|
internal void StartRelay() {
|
||||||
|
@ -105,7 +120,7 @@ namespace XIVChatPlugin {
|
||||||
this.Server.Spawn();
|
this.Server.Spawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RelaunchServer() {
|
internal void RelaunchServer() {
|
||||||
this.Server.Dispose();
|
this.Server.Dispose();
|
||||||
this.LaunchServer();
|
this.LaunchServer();
|
||||||
}
|
}
|
||||||
|
@ -113,34 +128,5 @@ namespace XIVChatPlugin {
|
||||||
private void OnCommand(string command, string args) {
|
private void OnCommand(string command, string args) {
|
||||||
this.Ui.OpenSettings(null, null);
|
this.Ui.OpenSettings(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "DelegateSubtraction")]
|
|
||||||
protected virtual void Dispose(bool disposing) {
|
|
||||||
if (this._disposedValue) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disposing) {
|
|
||||||
this.Relay?.Dispose();
|
|
||||||
this.Server.Dispose();
|
|
||||||
|
|
||||||
this.Interface.UiBuilder.OnBuildUi -= this.Ui.Draw;
|
|
||||||
this.Interface.UiBuilder.OnOpenConfigUi -= this.Ui.OpenSettings;
|
|
||||||
this.Interface.Framework.OnUpdateEvent -= this.Server.OnFrameworkUpdate;
|
|
||||||
this.Interface.Framework.Gui.Chat.OnChatMessage -= this.Server.OnChat;
|
|
||||||
this.Interface.ClientState.OnLogin -= this.Server.OnLogIn;
|
|
||||||
this.Interface.ClientState.OnLogout -= this.Server.OnLogOut;
|
|
||||||
this.Interface.ClientState.TerritoryChanged -= this.Server.OnTerritoryChange;
|
|
||||||
this.Interface.CommandManager.RemoveHandler("/xivchat");
|
|
||||||
}
|
|
||||||
|
|
||||||
this._disposedValue = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose() {
|
|
||||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
|
||||||
this.Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace XIVChatPlugin {
|
namespace XIVChatPlugin {
|
||||||
public class PluginUi {
|
internal class PluginUi {
|
||||||
private Plugin Plugin { get; }
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
private bool _showSettings;
|
private bool _showSettings;
|
||||||
|
@ -21,23 +21,23 @@ namespace XIVChatPlugin {
|
||||||
private readonly Dictionary<Guid, Tuple<BaseClient, Channel<bool>>> _pending = new();
|
private readonly Dictionary<Guid, Tuple<BaseClient, Channel<bool>>> _pending = new();
|
||||||
private readonly Dictionary<Guid, string> _pendingNames = new(0);
|
private readonly Dictionary<Guid, string> _pendingNames = new(0);
|
||||||
|
|
||||||
public PluginUi(Plugin plugin) {
|
internal PluginUi(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");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Colours {
|
private static class Colours {
|
||||||
public static readonly Vector4 Primary = new(2 / 255f, 204 / 255f, 238 / 255f, 1.0f);
|
internal static readonly Vector4 Primary = new(2 / 255f, 204 / 255f, 238 / 255f, 1.0f);
|
||||||
public static readonly Vector4 PrimaryDark = new(2 / 255f, 180 / 255f, 211 / 255f, 1.0f);
|
internal static readonly Vector4 PrimaryDark = new(2 / 255f, 180 / 255f, 211 / 255f, 1.0f);
|
||||||
public static readonly Vector4 Background = new(46 / 255f, 46 / 255f, 46 / 255f, 1.0f);
|
internal static readonly Vector4 Background = new(46 / 255f, 46 / 255f, 46 / 255f, 1.0f);
|
||||||
public static readonly Vector4 Text = new(190 / 255f, 190 / 255f, 190 / 255f, 1.0f);
|
internal static readonly Vector4 Text = new(190 / 255f, 190 / 255f, 190 / 255f, 1.0f);
|
||||||
public static readonly Vector4 Button = new(90 / 255f, 89 / 255f, 90 / 255f, 1.0f);
|
internal static readonly Vector4 Button = new(90 / 255f, 89 / 255f, 90 / 255f, 1.0f);
|
||||||
public static readonly Vector4 ButtonActive = new(123 / 255f, 122 / 255f, 124 / 255f, 1.0f);
|
internal static readonly Vector4 ButtonActive = new(123 / 255f, 122 / 255f, 124 / 255f, 1.0f);
|
||||||
public static readonly Vector4 ButtonHovered = new(108 / 255f, 107 / 255f, 109 / 255f, 1.0f);
|
internal static readonly Vector4 ButtonHovered = new(108 / 255f, 107 / 255f, 109 / 255f, 1.0f);
|
||||||
|
|
||||||
public static readonly Vector4 White = new(1f, 1f, 1f, 1f);
|
internal static readonly Vector4 White = new(1f, 1f, 1f, 1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw() {
|
internal void Draw() {
|
||||||
ImGui.PushStyleColor(ImGuiCol.TitleBg, Colours.PrimaryDark);
|
ImGui.PushStyleColor(ImGuiCol.TitleBg, Colours.PrimaryDark);
|
||||||
ImGui.PushStyleColor(ImGuiCol.TitleBgActive, Colours.Primary);
|
ImGui.PushStyleColor(ImGuiCol.TitleBgActive, Colours.Primary);
|
||||||
ImGui.PushStyleColor(ImGuiCol.TitleBgCollapsed, Colours.PrimaryDark);
|
ImGui.PushStyleColor(ImGuiCol.TitleBgCollapsed, Colours.PrimaryDark);
|
||||||
|
@ -102,7 +102,7 @@ namespace XIVChatPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.ShowSettings || !Begin(this.Plugin.Name, ref this._showSettings, ImGuiWindowFlags.AlwaysAutoResize)) {
|
if (!this.ShowSettings || !Begin(this.Plugin.DalamudPlugin.Name, ref this._showSettings, ImGuiWindowFlags.AlwaysAutoResize)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,21 +10,21 @@ using WebSocketSharp;
|
||||||
using XIVChatCommon.Message.Relay;
|
using XIVChatCommon.Message.Relay;
|
||||||
|
|
||||||
namespace XIVChatPlugin {
|
namespace XIVChatPlugin {
|
||||||
public enum ConnectionStatus {
|
internal enum ConnectionStatus {
|
||||||
Disconnected,
|
Disconnected,
|
||||||
Connecting,
|
Connecting,
|
||||||
Negotiating,
|
Negotiating,
|
||||||
Connected,
|
Connected,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Relay : IDisposable {
|
internal class Relay : IDisposable {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
private const string RelayUrl = "ws://localhost:14555/";
|
private const string RelayUrl = "ws://localhost:14555/";
|
||||||
#else
|
#else
|
||||||
private const string RelayUrl = "wss://relay.xiv.chat/";
|
private const string RelayUrl = "wss://relay.xiv.chat/";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public static string? ConnectionError { get; private set; }
|
internal static string? ConnectionError { get; private set; }
|
||||||
|
|
||||||
private bool Disposed { get; set; }
|
private bool Disposed { get; set; }
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace XIVChatPlugin {
|
||||||
|
|
||||||
private bool Running { get; set; }
|
private bool Running { get; set; }
|
||||||
|
|
||||||
public ConnectionStatus Status { get; private set; }
|
internal ConnectionStatus Status { get; private set; }
|
||||||
|
|
||||||
private Channel<IToRelay> ToRelay { get; } = Channel.CreateUnbounded<IToRelay>();
|
private Channel<IToRelay> ToRelay { get; } = Channel.CreateUnbounded<IToRelay>();
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ using XIVChatCommon.Message.Client;
|
||||||
using XIVChatCommon.Message.Server;
|
using XIVChatCommon.Message.Server;
|
||||||
|
|
||||||
namespace XIVChatPlugin {
|
namespace XIVChatPlugin {
|
||||||
public class Server : IDisposable {
|
internal class Server : IDisposable {
|
||||||
private const int MaxMessageLength = 500;
|
private const int MaxMessageLength = 500;
|
||||||
|
|
||||||
private static readonly string[] PublicPrefixes = {
|
private static readonly string[] PublicPrefixes = {
|
||||||
|
@ -47,8 +47,8 @@ namespace XIVChatPlugin {
|
||||||
private readonly ConcurrentQueue<string> _toGame = new();
|
private readonly ConcurrentQueue<string> _toGame = new();
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<Guid, BaseClient> _clients = new();
|
private readonly ConcurrentDictionary<Guid, BaseClient> _clients = new();
|
||||||
public IReadOnlyDictionary<Guid, BaseClient> Clients => this._clients;
|
internal IReadOnlyDictionary<Guid, BaseClient> Clients => this._clients;
|
||||||
public readonly Channel<Tuple<BaseClient, Channel<bool>>> PendingClients = Channel.CreateUnbounded<Tuple<BaseClient, Channel<bool>>>();
|
internal readonly Channel<Tuple<BaseClient, Channel<bool>>> PendingClients = Channel.CreateUnbounded<Tuple<BaseClient, Channel<bool>>>();
|
||||||
|
|
||||||
private readonly HashSet<Guid> _waitingForFriendList = new();
|
private readonly HashSet<Guid> _waitingForFriendList = new();
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ namespace XIVChatPlugin {
|
||||||
|
|
||||||
private const int MaxMessageSize = 128_000;
|
private const int MaxMessageSize = 128_000;
|
||||||
|
|
||||||
public Server(Plugin plugin) {
|
internal Server(Plugin plugin) {
|
||||||
this._plugin = plugin;
|
this._plugin = plugin;
|
||||||
if (this._plugin.Config.KeyPair == null) {
|
if (this._plugin.Config.KeyPair == null) {
|
||||||
this.RegenerateKeyPair();
|
this.RegenerateKeyPair();
|
||||||
|
@ -167,7 +167,7 @@ namespace XIVChatPlugin {
|
||||||
this._waitingForFriendList.Clear();
|
this._waitingForFriendList.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Spawn() {
|
internal void Spawn() {
|
||||||
var port = this._plugin.Config.Port;
|
var port = this._plugin.Config.Port;
|
||||||
|
|
||||||
Task.Run(async () => {
|
Task.Run(async () => {
|
||||||
|
@ -191,13 +191,12 @@ namespace XIVChatPlugin {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegenerateKeyPair() {
|
internal void RegenerateKeyPair() {
|
||||||
this._plugin.Config.KeyPair = PublicKeyBox.GenerateKeyPair();
|
this._plugin.Config.KeyPair = PublicKeyBox.GenerateKeyPair();
|
||||||
this._plugin.Config.Save();
|
this._plugin.Config.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "delegate")]
|
internal void OnChat(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled) {
|
||||||
public void OnChat(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled) {
|
|
||||||
if (isHandled) {
|
if (isHandled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -245,8 +244,7 @@ namespace XIVChatPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "delegate")]
|
internal void OnFrameworkUpdate(Framework framework) {
|
||||||
public void OnFrameworkUpdate(Framework framework) {
|
|
||||||
var player = this._plugin.Interface.ClientState.LocalPlayer;
|
var player = this._plugin.Interface.ClientState.LocalPlayer;
|
||||||
if (player != null && this._sendPlayerData) {
|
if (player != null && this._sendPlayerData) {
|
||||||
this.BroadcastPlayerData();
|
this.BroadcastPlayerData();
|
||||||
|
@ -482,7 +480,7 @@ namespace XIVChatPlugin {
|
||||||
this._waitingForFriendList.Add(id);
|
this._waitingForFriendList.Add(id);
|
||||||
|
|
||||||
if (!this._plugin.Functions.RequestingFriendList && !this._plugin.Functions.RequestFriendList()) {
|
if (!this._plugin.Functions.RequestingFriendList && !this._plugin.Functions.RequestFriendList()) {
|
||||||
this._plugin.Interface.Framework.Gui.Chat.PrintError($"[{this._plugin.Name}] Please open your friend list to enable friend list support. You should only need to do this on initial install or after updates.");
|
this._plugin.Interface.Framework.Gui.Chat.PrintError($"[{this._plugin.DalamudPlugin.Name}] Please open your friend list to enable friend list support. You should only need to do this on initial install or after updates.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,18 +498,18 @@ namespace XIVChatPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NameFormatting {
|
internal class NameFormatting {
|
||||||
public string Before { get; private set; } = string.Empty;
|
internal string Before { get; private set; } = string.Empty;
|
||||||
public string After { get; private set; } = string.Empty;
|
internal string After { get; private set; } = string.Empty;
|
||||||
public bool IsPresent { get; private set; } = true;
|
internal bool IsPresent { get; private set; } = true;
|
||||||
|
|
||||||
public static NameFormatting Empty() {
|
internal static NameFormatting Empty() {
|
||||||
return new() {
|
return new() {
|
||||||
IsPresent = false,
|
IsPresent = false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NameFormatting Of(string before, string after) {
|
internal static NameFormatting Of(string before, string after) {
|
||||||
return new() {
|
return new() {
|
||||||
Before = before,
|
Before = before,
|
||||||
After = after,
|
After = after,
|
||||||
|
@ -750,7 +748,7 @@ namespace XIVChatPlugin {
|
||||||
return this._plugin.Interface.Data.GetExcelSheet<LogFilter>().GetRow(rowId).Name;
|
return this._plugin.Interface.Data.GetExcelSheet<LogFilter>().GetRow(rowId).Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnChatChannelChange(uint channel) {
|
internal void OnChatChannelChange(uint channel) {
|
||||||
var inputChannel = (InputChannel) channel;
|
var inputChannel = (InputChannel) channel;
|
||||||
this._currentChannel = inputChannel;
|
this._currentChannel = inputChannel;
|
||||||
|
|
||||||
|
@ -785,18 +783,18 @@ namespace XIVChatPlugin {
|
||||||
this.BroadcastMessage(playerData);
|
this.BroadcastMessage(playerData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnLogIn(object sender, EventArgs e) {
|
internal void OnLogIn(object sender, EventArgs e) {
|
||||||
this.BroadcastAvailability(true);
|
this.BroadcastAvailability(true);
|
||||||
// send player data on next framework update
|
// send player data on next framework update
|
||||||
this._sendPlayerData = true;
|
this._sendPlayerData = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnLogOut(object sender, EventArgs e) {
|
internal void OnLogOut(object sender, EventArgs e) {
|
||||||
this.BroadcastAvailability(false);
|
this.BroadcastAvailability(false);
|
||||||
this.BroadcastPlayerData();
|
this.BroadcastPlayerData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnTerritoryChange(object sender, ushort territoryId) => this._sendPlayerData = true;
|
internal void OnTerritoryChange(object sender, ushort territoryId) => this._sendPlayerData = true;
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
// stop accepting new clients
|
// stop accepting new clients
|
||||||
|
@ -822,7 +820,7 @@ namespace XIVChatPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class TcpListenerExt {
|
internal static class TcpListenerExt {
|
||||||
public static async Task<TcpClient?> GetTcpClient(this TcpListener listener, CancellationTokenSource source) {
|
internal static async Task<TcpClient?> GetTcpClient(this TcpListener listener, CancellationTokenSource source) {
|
||||||
using (source.Token.Register(listener.Stop)) {
|
using (source.Token.Register(listener.Stop)) {
|
||||||
try {
|
try {
|
||||||
var client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
|
var client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
|
||||||
|
|
|
@ -5,11 +5,11 @@ using System.Numerics;
|
||||||
|
|
||||||
namespace XIVChatPlugin {
|
namespace XIVChatPlugin {
|
||||||
internal static class Util {
|
internal static class Util {
|
||||||
public static string ToHexString(this IEnumerable<byte> bytes, bool upper = false, string separator = "") {
|
internal static string ToHexString(this IEnumerable<byte> bytes, bool upper = false, string separator = "") {
|
||||||
return string.Join(separator, bytes.Select(b => b.ToString(upper ? "X2" : "x2")));
|
return string.Join(separator, bytes.Select(b => b.ToString(upper ? "X2" : "x2")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Vector4> ToColours(this byte[] bytes) {
|
internal static List<Vector4> ToColours(this byte[] bytes) {
|
||||||
var colours = new List<Vector4>();
|
var colours = new List<Vector4>();
|
||||||
|
|
||||||
var colour = new Vector4(0f, 0f, 0f, 1f);
|
var colour = new Vector4(0f, 0f, 0f, 1f);
|
||||||
|
@ -41,7 +41,7 @@ namespace XIVChatPlugin {
|
||||||
return colours;
|
return colours;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int IndexOfCount(this string source, char toFind, int position) {
|
internal static int IndexOfCount(this string source, char toFind, int position) {
|
||||||
var index = -1;
|
var index = -1;
|
||||||
for (var i = 0; i < position; i++) {
|
for (var i = 0; i < position; i++) {
|
||||||
index = source.IndexOf(toFind, index + 1);
|
index = source.IndexOf(toFind, index + 1);
|
||||||
|
@ -54,14 +54,14 @@ namespace XIVChatPlugin {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] Terminate(this byte[] bytes) {
|
internal static byte[] Terminate(this byte[] bytes) {
|
||||||
var terminated = new byte[bytes.Length + 1];
|
var terminated = new byte[bytes.Length + 1];
|
||||||
Array.Copy(bytes, terminated, bytes.Length);
|
Array.Copy(bytes, terminated, bytes.Length);
|
||||||
terminated[terminated.Length - 1] = 0;
|
terminated[terminated.Length - 1] = 0;
|
||||||
return terminated;
|
return terminated;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe byte[] ReadTerminated(byte* mem) {
|
internal static unsafe byte[] ReadTerminated(byte* mem) {
|
||||||
var bytes = new List<byte>();
|
var bytes = new List<byte>();
|
||||||
while (*mem != 0) {
|
while (*mem != 0) {
|
||||||
bytes.Add(*mem);
|
bytes.Add(*mem);
|
||||||
|
|
|
@ -29,20 +29,21 @@
|
||||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath>
|
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DalamudPackager" Version="1.2.1"/>
|
<PackageReference Include="DalamudPackager" Version="1.2.1" />
|
||||||
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.18.2"/>
|
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.18.2" />
|
||||||
<PackageReference Include="MessagePack" Version="2.2.85"/>
|
<PackageReference Include="MessagePack" Version="2.2.85" />
|
||||||
<PackageReference Include="Sodium.Core" Version="1.2.3"/>
|
<PackageReference Include="Sodium.Core" Version="1.2.3" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="5.0.0"/>
|
<PackageReference Include="System.Threading.Channels" Version="5.0.0" />
|
||||||
<PackageReference Include="WebSocketSharp" Version="1.0.3-rc11"/>
|
<PackageReference Include="WebSocketSharp" Version="1.0.3-rc11" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\XIVChatCommon\XIVChatCommon.csproj"/>
|
<ProjectReference Include="..\XIVChatCommon\XIVChatCommon.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Target Name="CopyNativeLibraries" AfterTargets="AfterBuild">
|
<Target Name="CopyNativeLibraries" AfterTargets="AfterBuild">
|
||||||
<Copy SourceFiles="Resources\lib\libsodium.dll" DestinationFolder="$(OutDir)"/>
|
<Copy SourceFiles="Resources\lib\libsodium.dll" DestinationFolder="$(OutDir)" />
|
||||||
<Copy SourceFiles="Resources\lib\xivchat_native_tools.dll" DestinationFolder="$(OutDir)"/>
|
<Copy SourceFiles="Resources\lib\xivchat_native_tools.dll" DestinationFolder="$(OutDir)" />
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in New Issue