refactor: further update for net5

This commit is contained in:
Anna 2021-09-10 10:36:49 -04:00
parent 2807f695ae
commit fec2674854
11 changed files with 246 additions and 197 deletions

View File

@ -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();
internal 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;

View File

@ -1,29 +0,0 @@
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;
}
}
}

View File

@ -6,7 +6,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using Dalamud.Plugin; using Dalamud.Logging;
using XIVChatCommon.Message; using XIVChatCommon.Message;
namespace XIVChatPlugin { namespace XIVChatPlugin {
@ -142,37 +142,37 @@ namespace XIVChatPlugin {
} }
if (friendListPtr != IntPtr.Zero) { if (friendListPtr != IntPtr.Zero) {
this._friendListHook = new Hook<RequestFriendListDelegate>(friendListPtr, new RequestFriendListDelegate(this.OnRequestFriendList)); this._friendListHook = new Hook<RequestFriendListDelegate>(friendListPtr, this.OnRequestFriendList);
} else { } else {
PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(friendListPtr)); PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(friendListPtr));
} }
if (formatPtr != IntPtr.Zero) { if (formatPtr != IntPtr.Zero) {
this._formatHook = new Hook<FormatFriendListNameDelegate>(formatPtr, new FormatFriendListNameDelegate(this.OnFormatFriendList)); this._formatHook = new Hook<FormatFriendListNameDelegate>(formatPtr, this.OnFormatFriendList);
} else { } else {
PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(formatPtr)); PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(formatPtr));
} }
if (recvChunkPtr != IntPtr.Zero) { if (recvChunkPtr != IntPtr.Zero) {
this._receiveChunkHook = new Hook<OnReceiveFriendListChunkDelegate>(recvChunkPtr, new OnReceiveFriendListChunkDelegate(this.OnReceiveFriendList)); this._receiveChunkHook = new Hook<OnReceiveFriendListChunkDelegate>(recvChunkPtr, this.OnReceiveFriendList);
} else { } else {
PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(recvChunkPtr)); PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(recvChunkPtr));
} }
if (channelPtr != IntPtr.Zero) { if (channelPtr != IntPtr.Zero) {
this._chatChannelChangeHook = new Hook<ChatChannelChangeDelegate>(channelPtr, new ChatChannelChangeDelegate(this.ChangeChatChannelDetour)); this._chatChannelChangeHook = new Hook<ChatChannelChangeDelegate>(channelPtr, this.ChangeChatChannelDetour);
} else { } else {
PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(channelPtr)); PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(channelPtr));
} }
if (inputPtr != IntPtr.Zero) { if (inputPtr != IntPtr.Zero) {
this._isInputHook = new Hook<IsInputDelegate>(inputPtr, new IsInputDelegate(this.IsInputDetour)); this._isInputHook = new Hook<IsInputDelegate>(inputPtr, this.IsInputDetour);
} else { } else {
PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(inputPtr)); PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(inputPtr));
} }
if (inputAfkPtr != IntPtr.Zero) { if (inputAfkPtr != IntPtr.Zero) {
this._isInputAfkHook = new Hook<IsInputAfkDelegate>(inputAfkPtr, new IsInputAfkDelegate(this.IsInputAfkDetour)); this._isInputAfkHook = new Hook<IsInputAfkDelegate>(inputAfkPtr, this.IsInputAfkDetour);
} else { } else {
PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(inputAfkPtr)); PluginLog.Warning("Pointer was null, disabling hook: {0}", nameof(inputAfkPtr));
} }
@ -220,7 +220,7 @@ namespace XIVChatPlugin {
// //
// If this function would ever return 0, it returns null instead. // If this function would ever return 0, it returns null instead.
internal uint? GetChannelColour(ChatCode channel) { internal uint? GetChannelColour(ChatCode channel) {
if (this.ColourLookup == IntPtr.Zero || this.ColourHandler == IntPtr.Zero) { if (this._getColourInfo == null || this.ColourLookup == IntPtr.Zero || this.ColourHandler == IntPtr.Zero) {
return null; return null;
} }
@ -250,7 +250,7 @@ namespace XIVChatPlugin {
} }
internal void ProcessChatBox(string message) { internal void ProcessChatBox(string message) {
if (this._easierProcessChatBox == null || this.UiModulePtr == IntPtr.Zero) { if (this._easierProcessChatBox == null || this._getUiModule == null || this.UiModulePtr == IntPtr.Zero) {
return; return;
} }
@ -307,13 +307,13 @@ namespace XIVChatPlugin {
string? jobName = null; string? jobName = null;
if (entry.job > 0) { if (entry.job > 0) {
jobName = this.Plugin.Interface.Data.GetExcelSheet<ClassJob>().GetRow(entry.job)?.Name; jobName = this.Plugin.DataManager.GetExcelSheet<ClassJob>()!.GetRow(entry.job)?.Name?.ToString();
} }
// FIXME: remove this try/catch when lumina fixes bug with .Value // FIXME: remove this try/catch when lumina fixes bug with .Value
string? territoryName; string? territoryName;
try { try {
territoryName = this.Plugin.Interface.Data.GetExcelSheet<TerritoryType>().GetRow(entry.territoryId)?.PlaceName?.Value?.Name; territoryName = this.Plugin.DataManager.GetExcelSheet<TerritoryType>()!.GetRow(entry.territoryId)?.PlaceName?.Value?.Name?.ToString();
} catch (NullReferenceException) { } catch (NullReferenceException) {
territoryName = null; territoryName = null;
} }
@ -324,9 +324,9 @@ namespace XIVChatPlugin {
Status = entry.flags, Status = entry.flags,
CurrentWorld = entry.currentWorldId, CurrentWorld = entry.currentWorldId,
CurrentWorldName = this.Plugin.Interface.Data.GetExcelSheet<World>().GetRow(entry.currentWorldId)?.Name, CurrentWorldName = this.Plugin.DataManager.GetExcelSheet<World>()!.GetRow(entry.currentWorldId)?.Name?.ToString(),
HomeWorld = entry.homeWorldId, HomeWorld = entry.homeWorldId,
HomeWorldName = this.Plugin.Interface.Data.GetExcelSheet<World>().GetRow(entry.homeWorldId)?.Name, HomeWorldName = this.Plugin.DataManager.GetExcelSheet<World>()!.GetRow(entry.homeWorldId)?.Name?.ToString(),
Territory = entry.territoryId, Territory = entry.territoryId,
TerritoryName = territoryName, TerritoryName = territoryName,
@ -335,7 +335,7 @@ namespace XIVChatPlugin {
JobName = jobName, JobName = jobName,
GrandCompany = entry.grandCompany, GrandCompany = entry.grandCompany,
GrandCompanyName = this.Plugin.Interface.Data.GetExcelSheet<GrandCompany>().GetRow(entry.grandCompany)?.Name, GrandCompanyName = this.Plugin.DataManager.GetExcelSheet<GrandCompany>()!.GetRow(entry.grandCompany)?.Name?.ToString(),
Languages = entry.langsEnabled, Languages = entry.langsEnabled,
MainLanguage = entry.mainLanguage, MainLanguage = entry.mainLanguage,

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="ILRepacker" AfterTargets="Build">
<ItemGroup>
<InputAssemblies Include="$(OutputPath)\$(AssemblyName).dll"/>
<InputAssemblies Include="$(OutputPath)\*.dll"
Exclude="$(OutputPath)\$(AssemblyName).dll;
$(OutputPath)\libsodium.dll;
$(OutputPath)\xivchat_native_tools.dll;
$(OutputPath)\System.Buffers.dll;
$(OutputPath)\System.Memory.dll;
$(OutputPath)\System.Numerics.Vectors.dll"/>
</ItemGroup>
<ILRepack
Parallel="true"
Internalize="false"
InputAssemblies="@(InputAssemblies)"
TargetKind="Dll"
TargetPlatformVersion="v4"
LibraryPath="$(OutputPath)"
DebugInfo="true"
OutputFile="$(OutputPath)\$(AssemblyName).dll"/>
<Delete Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')"/>
<ItemGroup>
<Directories Include="$([System.IO.Directory]::GetDirectories('$(OutDir)%(DestinationSubDirectory)', '*', System.IO.SearchOption.AllDirectories))"/>
<Directories>
<Files>$([System.IO.Directory]::GetFiles("%(Directories.Identity)", "*", System.IO.SearchOption.AllDirectories).get_Length())</Files>
</Directories>
</ItemGroup>
</Target>
</Project>

View File

@ -0,0 +1,13 @@
using System;
namespace XIVChatPlugin {
internal class InternalEvents {
internal delegate void NewClientDelegate(Guid id, BaseClient client);
internal event NewClientDelegate? NewClient;
internal void FireNewClientEvent(Guid id, BaseClient client) {
this.NewClient?.Invoke(id, client);
}
}
}

View File

@ -1,9 +1,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Dynamic;
using System.Linq; using System.Linq;
using Dalamud.Game.ClientState.Actors.Types; using Dalamud.Game.ClientState.Objects.SubKinds;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using PeepingTom.Ipc;
using PeepingTom.Ipc.From;
using PeepingTom.Ipc.To;
using XIVChatCommon.Message; using XIVChatCommon.Message;
using XIVChatCommon.Message.Client; using XIVChatCommon.Message.Client;
using XIVChatCommon.Message.Server; using XIVChatCommon.Message.Server;
@ -11,38 +13,84 @@ using XIVChatCommon.Message.Server;
namespace XIVChatPlugin.Ipc { namespace XIVChatPlugin.Ipc {
internal class PeepingTom : IDisposable { internal class PeepingTom : IDisposable {
private Plugin Plugin { get; } private Plugin Plugin { get; }
private List<TargeterWithStatus> Targeters { get; } = new();
private class TargeterWithStatus {
public Targeter Targeter { get; set; } = null!;
public bool Targeting { get; set; }
}
internal PeepingTom(Plugin plugin) { internal PeepingTom(Plugin plugin) {
this.Plugin = plugin; this.Plugin = plugin;
#pragma warning disable 618 IpcInfo.GetSubscriber(this.Plugin.Interface).Subscribe(this.ReceiveMessage);
this.Plugin.Interface.Subscribe("PeepingTom", this.ReceiveTargeting); IpcInfo.GetProvider(this.Plugin.Interface).SendMessage(new RequestTargetersMessage());
#pragma warning restore 618 this.Plugin.Events.NewClient += this.OnNewClient;
} }
public void Dispose() { public void Dispose() {
#pragma warning disable 618 this.Plugin.Events.NewClient -= this.OnNewClient;
this.Plugin.Interface.Unsubscribe("PeepingTom"); IpcInfo.GetSubscriber(this.Plugin.Interface).Unsubscribe(this.ReceiveMessage);
#pragma warning restore 618
} }
private void ReceiveTargeting(dynamic obj) { private void ReceiveMessage(IFromMessage message) {
List<ExpandoObject> list = obj.Targeting; switch (message) {
var players = list case AllTargetersMessage allMessage: {
.Select((dynamic player) => (uint) player.ActorId) this.Targeters.Clear();
.Select(targeting => this.Plugin.Interface.ClientState.Actors.FirstOrDefault(actor => actor.ActorId == targeting)) this.Targeters.AddRange(allMessage.Targeters
.Select(t => new TargeterWithStatus {
Targeter = t.targeter,
Targeting = t.currentlyTargeting,
}));
break;
}
case NewTargeterMessage newMessage: {
this.UpdateTargeter(newMessage.Targeter, true);
break;
}
case StoppedTargetingMessage stoppedMessage: {
this.UpdateTargeter(stoppedMessage.Targeter, false);
break;
}
}
var xivChatMessage = this.GetMessage();
foreach (var client in this.Plugin.Server.Clients.Values) {
this.SendToClient(client, xivChatMessage);
}
}
private void UpdateTargeter(Targeter targeter, bool targeting) {
var existing = this.Targeters.FirstOrDefault(t => t.Targeter.ObjectId == targeter.ObjectId);
if (existing == default) {
this.Targeters.Add(new TargeterWithStatus {
Targeter = targeter,
Targeting = targeting,
});
} else {
existing.Targeter = targeter;
existing.Targeting = targeting;
}
}
private ServerPlayerList GetMessage() {
var players = this.Targeters
.Where(targeter => targeter.Targeting) // FIXME: send entire history so clients don't have to do logic
.Select(targeter => this.Plugin.ObjectTable.FirstOrDefault(obj => obj.ObjectId == targeter.Targeter.ObjectId))
.Where(actor => actor is PlayerCharacter) .Where(actor => actor is PlayerCharacter)
.Cast<PlayerCharacter>() .Cast<PlayerCharacter>()
.Select(chara => new Player { .Select(chara => new Player {
Name = chara.Name, Name = chara.Name.TextValue,
FreeCompany = chara.CompanyTag, FreeCompany = chara.CompanyTag.TextValue,
Status = 0, Status = 0,
CurrentWorld = (ushort) chara.CurrentWorld.Id, CurrentWorld = (ushort) chara.CurrentWorld.Id,
CurrentWorldName = chara.CurrentWorld.GameData.Name.ToString(), CurrentWorldName = chara.CurrentWorld.GameData.Name.ToString(),
HomeWorld = (ushort) chara.HomeWorld.Id, HomeWorld = (ushort) chara.HomeWorld.Id,
HomeWorldName = chara.HomeWorld.GameData.Name.ToString(), HomeWorldName = chara.HomeWorld.GameData.Name.ToString(),
Territory = this.Plugin.Interface.ClientState.TerritoryType, Territory = this.Plugin.ClientState.TerritoryType,
TerritoryName = this.Plugin.Interface.Data.GetExcelSheet<TerritoryType>().GetRow(this.Plugin.Interface.ClientState.TerritoryType)?.Name, TerritoryName = this.Plugin.DataManager.GetExcelSheet<TerritoryType>()!.GetRow(this.Plugin.ClientState.TerritoryType)?.Name?.ToString(),
Job = (byte) chara.ClassJob.Id, Job = (byte) chara.ClassJob.Id,
JobName = chara.ClassJob.GameData.Name.ToString(), JobName = chara.ClassJob.GameData.Name.ToString(),
GrandCompany = 0, GrandCompany = 0,
@ -51,14 +99,19 @@ namespace XIVChatPlugin.Ipc {
MainLanguage = 0, MainLanguage = 0,
}) })
.ToArray(); .ToArray();
return new ServerPlayerList(PlayerListType.Targeting, players);
}
foreach (var client in this.Plugin.Server.Clients.Values) { private void SendToClient(BaseClient client, ServerPlayerList list) {
if (!client.GetPreference(ClientPreference.TargetingListSupport, false)) { if (!client.GetPreference(ClientPreference.TargetingListSupport, false)) {
continue; return;
}
client.Queue.Writer.TryWrite(new ServerPlayerList(PlayerListType.Targeting, players));
} }
client.Queue.Writer.TryWrite(list);
}
private void OnNewClient(Guid id, BaseClient client) {
this.SendToClient(client, this.GetMessage());
} }
} }
} }

View File

@ -2,26 +2,69 @@
using Dalamud.Plugin; using Dalamud.Plugin;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Dalamud.Data;
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.Gui;
using Dalamud.IoC;
#if DEBUG #if DEBUG
using System.IO; using System.IO;
#endif #endif
namespace XIVChatPlugin { namespace XIVChatPlugin {
internal class Plugin : IDisposable { internal class Plugin : IDalamudPlugin {
public string Name => "XIVChat";
private bool _disposedValue; private bool _disposedValue;
internal DalamudPluginInterface Interface { get; } [PluginService]
internal DalamudPlugin DalamudPlugin { get; } internal DalamudPluginInterface Interface { get; private init; } = null!;
[PluginService]
internal ChatGui ChatGui { get; private init; } = null!;
[PluginService]
internal ClientState ClientState { get; private init; } = null!;
[PluginService]
private CommandManager CommandManager { get; init; } = null!;
[PluginService]
internal DataManager DataManager { get; private init; } = null!;
[PluginService]
private Framework Framework { get; init; } = null!;
[PluginService]
internal ObjectTable ObjectTable { get; private init; } = null!;
[PluginService]
private SigScanner SigScanner { get; init; } = null!;
internal Configuration Config { get; } internal Configuration Config { get; }
private PluginUi Ui { get; } private PluginUi Ui { get; }
internal Server Server { get; private set; } = null!; internal Server Server { get; private set; }
internal Relay? Relay { get; private set; } internal Relay? Relay { get; private set; }
internal GameFunctions Functions { get; } internal GameFunctions Functions { get; }
internal InternalEvents Events { get; }
private List<IDisposable> Ipcs { get; } = new(); private List<IDisposable> Ipcs { get; } = new();
internal Plugin(DalamudPlugin dalamudPlugin, DalamudPluginInterface pluginInterface) { // ReSharper disable once UnusedMember.Global
this.Interface = pluginInterface; // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Local
this.DalamudPlugin = dalamudPlugin; // ReSharper disable once UnusedAutoPropertyAccessor.Global
// ReSharper disable once MemberCanBePrivate.Global
internal string Location { get; private set; } = Assembly.GetExecutingAssembly().Location;
[SuppressMessage("ReSharper", "UnusedMember.Local")]
private void SetLocation(string path) {
this.Location = path;
}
public Plugin() {
this.Events = new InternalEvents();
// load libsodium.so from debug location if in debug mode // load libsodium.so from debug location if in debug mode
#if DEBUG #if DEBUG
@ -43,14 +86,14 @@ namespace XIVChatPlugin {
this.StartRelay(); this.StartRelay();
} }
this.Interface.UiBuilder.OnBuildUi += this.Ui.Draw; this.Interface.UiBuilder.Draw += this.Ui.Draw;
this.Interface.UiBuilder.OnOpenConfigUi += this.Ui.OpenSettings; this.Interface.UiBuilder.OpenConfigUi += this.Ui.OpenSettings;
this.Interface.Framework.OnUpdateEvent += this.Server.OnFrameworkUpdate; this.Framework.Update += this.Server!.OnFrameworkUpdate;
this.Interface.Framework.Gui.Chat.OnChatMessage += this.Server.OnChat; this.ChatGui.ChatMessage += this.Server.OnChat;
this.Interface.ClientState.OnLogin += this.Server.OnLogIn; this.ClientState.Login += this.Server.OnLogIn;
this.Interface.ClientState.OnLogout += this.Server.OnLogOut; this.ClientState.Logout += this.Server.OnLogOut;
this.Interface.ClientState.TerritoryChanged += this.Server.OnTerritoryChange; this.ClientState.TerritoryChanged += this.Server.OnTerritoryChange;
this.Interface.CommandManager.AddHandler("/xivchat", new CommandInfo(this.OnCommand) { this.CommandManager.AddHandler("/xivchat", new CommandInfo(this.OnCommand) {
HelpMessage = "Opens the config for the XIVChat plugin", HelpMessage = "Opens the config for the XIVChat plugin",
}); });
@ -67,14 +110,14 @@ namespace XIVChatPlugin {
this.Relay?.Dispose(); this.Relay?.Dispose();
this.Server.Dispose(); this.Server.Dispose();
this.Interface.UiBuilder.OnBuildUi -= this.Ui.Draw; this.Interface.UiBuilder.Draw -= this.Ui.Draw;
this.Interface.UiBuilder.OnOpenConfigUi -= this.Ui.OpenSettings; this.Interface.UiBuilder.OpenConfigUi -= this.Ui.OpenSettings;
this.Interface.Framework.OnUpdateEvent -= this.Server.OnFrameworkUpdate; this.Framework.Update -= this.Server.OnFrameworkUpdate;
this.Interface.Framework.Gui.Chat.OnChatMessage -= this.Server.OnChat; this.ChatGui.ChatMessage -= this.Server.OnChat;
this.Interface.ClientState.OnLogin -= this.Server.OnLogIn; this.ClientState.Login -= this.Server.OnLogIn;
this.Interface.ClientState.OnLogout -= this.Server.OnLogOut; this.ClientState.Logout -= this.Server.OnLogOut;
this.Interface.ClientState.TerritoryChanged -= this.Server.OnTerritoryChange; this.ClientState.TerritoryChanged -= this.Server.OnTerritoryChange;
this.Interface.CommandManager.RemoveHandler("/xivchat"); this.CommandManager.RemoveHandler("/xivchat");
foreach (var ipc in this.Ipcs) { foreach (var ipc in this.Ipcs) {
ipc.Dispose(); ipc.Dispose();
@ -101,7 +144,7 @@ namespace XIVChatPlugin {
internal IntPtr ScanText(string sig) { internal IntPtr ScanText(string sig) {
try { try {
return this.Interface.TargetModuleScanner.ScanText(sig); return this.SigScanner.ScanText(sig);
} catch (KeyNotFoundException) { } catch (KeyNotFoundException) {
return IntPtr.Zero; return IntPtr.Zero;
} }
@ -109,7 +152,7 @@ namespace XIVChatPlugin {
internal IntPtr GetStaticAddressFromSig(string sig) { internal IntPtr GetStaticAddressFromSig(string sig) {
try { try {
return this.Interface.TargetModuleScanner.GetStaticAddressFromSig(sig); return this.SigScanner.GetStaticAddressFromSig(sig);
} catch (KeyNotFoundException) { } catch (KeyNotFoundException) {
return IntPtr.Zero; return IntPtr.Zero;
} }
@ -126,7 +169,7 @@ namespace XIVChatPlugin {
} }
private void OnCommand(string command, string args) { private void OnCommand(string command, string args) {
this.Ui.OpenSettings(null, null); this.Ui.OpenSettings();
} }
} }
} }

View File

@ -102,7 +102,12 @@ namespace XIVChatPlugin {
} }
} }
if (!this.ShowSettings || !Begin(this.Plugin.DalamudPlugin.Name, ref this._showSettings, ImGuiWindowFlags.AlwaysAutoResize)) { if (!this.ShowSettings) {
return;
}
if (!Begin(this.Plugin.Name, ref this._showSettings, ImGuiWindowFlags.AlwaysAutoResize)) {
ImGui.End();
return; return;
} }
@ -345,16 +350,6 @@ namespace XIVChatPlugin {
} }
} }
if (WithWhiteText(() => ImGui.CollapsingHeader("ACT/Teamcraft issues?"))) {
ImGui.PushTextWrapPos(ImGui.GetFontSize() * 20);
ImGui.TextUnformatted("Click on the button below to visit a website showing a workaround for ACT and Teamcraft having issues.");
ImGui.PopTextWrapPos();
if (WithWhiteText(() => ImGui.Button("Open website"))) {
System.Diagnostics.Process.Start("https://xiv.chat/server/workaround");
}
}
ImGui.End(); ImGui.End();
} }
@ -391,7 +386,7 @@ namespace XIVChatPlugin {
ImGui.Dummy(new Vector2(0, 16 + spacing.Y * 2)); ImGui.Dummy(new Vector2(0, 16 + spacing.Y * 2));
} }
public void OpenSettings(object? sender, EventArgs? args) { public void OpenSettings() {
this.ShowSettings = true; this.ShowSettings = true;
} }
@ -437,7 +432,7 @@ namespace XIVChatPlugin {
ImGui.PopTextWrapPos(); ImGui.PopTextWrapPos();
if (!this._pendingNames.TryGetValue(id, out string name)) { if (!this._pendingNames.TryGetValue(id, out var name)) {
name = "No name"; name = "No name";
} }

View File

@ -2,9 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Security.Authentication;
using System.Threading;
using System.Threading.Channels; using System.Threading.Channels;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Plugin; using Dalamud.Logging;
using MessagePack; using MessagePack;
using WebSocketSharp; using WebSocketSharp;
using XIVChatCommon.Message.Relay; using XIVChatCommon.Message.Relay;
@ -19,9 +21,9 @@ namespace XIVChatPlugin {
internal class Relay : IDisposable { internal class Relay : IDisposable {
#if DEBUG #if DEBUG
private const string RelayUrl = "ws://localhost:14555/"; private static readonly Uri RelayUrl = new("ws://localhost:14555/", UriKind.Absolute);
#else #else
private const string RelayUrl = "wss://relay.xiv.chat/"; private static readonly Uri RelayUrl = new("wss://relay.xiv.chat/", UriKind.Absolute);
#endif #endif
internal static string? ConnectionError { get; private set; } internal static string? ConnectionError { get; private set; }
@ -41,9 +43,9 @@ namespace XIVChatPlugin {
internal Relay(Plugin plugin) { internal Relay(Plugin plugin) {
this.Plugin = plugin; this.Plugin = plugin;
this.Connection = new WebSocket(RelayUrl) { this.Connection = new WebSocket(RelayUrl.ToString()) {
SslConfiguration = { SslConfiguration = {
EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12, EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13,
}, },
}; };
@ -55,7 +57,7 @@ namespace XIVChatPlugin {
public void Dispose() { public void Dispose() {
this.Disposed = true; this.Disposed = true;
this.Connection.CloseAsync(); new Thread(() => this.Connection.Close(CloseStatusCode.Normal)).Start();
this.Running = false; this.Running = false;
} }
@ -67,7 +69,7 @@ namespace XIVChatPlugin {
this.Running = true; this.Running = true;
this.Status = ConnectionStatus.Connecting; this.Status = ConnectionStatus.Connecting;
this.Connection.ConnectAsync(); new Thread(() => this.Connection.Connect()).Start();
} }
internal void ResendPublicKey() { internal void ResendPublicKey() {
@ -94,7 +96,7 @@ namespace XIVChatPlugin {
this.Connection.Send(bytes); this.Connection.Send(bytes);
} }
private void OnOpen(object sender, EventArgs e) { private void OnOpen(object? o, EventArgs eventArgs) {
this.Status = ConnectionStatus.Negotiating; this.Status = ConnectionStatus.Negotiating;
var auth = this.Plugin.Config.RelayAuth; var auth = this.Plugin.Config.RelayAuth;
@ -132,8 +134,8 @@ namespace XIVChatPlugin {
}); });
} }
private void OnMessage(object sender, MessageEventArgs e) { private void OnMessage(object? sender, MessageEventArgs args) {
var message = MessagePackSerializer.Deserialize<IFromRelay>(e.RawData); var message = MessagePackSerializer.Deserialize<IFromRelay>(args.RawData);
switch (message) { switch (message) {
case RelaySuccess success: case RelaySuccess success:
if (success.Success) { if (success.Success) {
@ -148,7 +150,9 @@ namespace XIVChatPlugin {
break; break;
case RelayNewClient newClient: case RelayNewClient newClient:
#pragma warning disable CA1806
IPAddress.TryParse(newClient.Address, out var remote); IPAddress.TryParse(newClient.Address, out var remote);
#pragma warning restore CA1806
var client = new RelayConnected( var client = new RelayConnected(
newClient.PublicKey.ToArray(), newClient.PublicKey.ToArray(),
remote, remote,
@ -181,17 +185,17 @@ namespace XIVChatPlugin {
} }
} }
private void OnClose(object sender, CloseEventArgs e) { private void OnClose(object? sender, CloseEventArgs args) {
this.Running = false; this.Running = false;
this.Status = ConnectionStatus.Disconnected; this.Status = ConnectionStatus.Disconnected;
if (!e.WasClean && !this.Disposed) { if (!args.WasClean && !this.Disposed) {
Task.Run(async () => await Task.Delay(3_000)).ContinueWith(_ => this.Start()); Task.Run(async () => await Task.Delay(3_000)).ContinueWith(_ => this.Start());
} }
} }
private void OnError(object sender, ErrorEventArgs e) { private void OnError(object? sender, ErrorEventArgs args) {
PluginLog.LogError(e.Exception, $"Error in relay connection: {e.Message}"); PluginLog.LogError(args.Exception, $"Error in relay connection: {args.Message}");
this.Running = false; this.Running = false;
this.Status = ConnectionStatus.Disconnected; this.Status = ConnectionStatus.Disconnected;

View File

@ -1,6 +1,4 @@
using Dalamud.Game.Internal; using Lumina.Excel.GeneratedSheets;
using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets;
using MessagePack; using MessagePack;
using Sodium; using Sodium;
using System; using System;
@ -14,9 +12,11 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Channels; using System.Threading.Channels;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Game;
using Dalamud.Game.Text; using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Logging;
using XIVChatCommon; using XIVChatCommon;
using XIVChatCommon.Message; using XIVChatCommon.Message;
using XIVChatCommon.Message.Client; using XIVChatCommon.Message.Client;
@ -91,7 +91,7 @@ namespace XIVChatPlugin {
var multicastAddr = IPAddress.Parse("224.0.0.147"); var multicastAddr = IPAddress.Parse("224.0.0.147");
udp.JoinMulticastGroup(multicastAddr); udp.JoinMulticastGroup(multicastAddr);
string? lastPlayerName = null; SeString? lastPlayerName = null;
Task<UdpReceiveResult>? receiveTask = null; Task<UdpReceiveResult>? receiveTask = null;
@ -101,7 +101,7 @@ namespace XIVChatPlugin {
continue; continue;
} }
var playerName = this._plugin.Interface.ClientState.LocalPlayer?.Name; var playerName = this._plugin.ClientState.LocalPlayer?.Name;
if (playerName != null) { if (playerName != null) {
lastPlayerName = playerName; lastPlayerName = playerName;
@ -135,7 +135,7 @@ namespace XIVChatPlugin {
continue; continue;
} }
var utf8 = Encoding.UTF8.GetBytes(lastPlayerName); var utf8 = Encoding.UTF8.GetBytes(lastPlayerName.TextValue);
var portBytes = BitConverter.GetBytes(this._plugin.Config.Port).Reverse().ToArray(); var portBytes = BitConverter.GetBytes(this._plugin.Config.Port).Reverse().ToArray();
var key = this._plugin.Config.KeyPair!.PublicKey; var key = this._plugin.Config.KeyPair!.PublicKey;
// magic + string length + string + port + key // magic + string length + string + port + key
@ -244,8 +244,8 @@ namespace XIVChatPlugin {
} }
} }
internal void OnFrameworkUpdate(Framework framework) { internal void OnFrameworkUpdate(Framework framework1) {
var player = this._plugin.Interface.ClientState.LocalPlayer; var player = this._plugin.ClientState.LocalPlayer;
if (player != null && this._sendPlayerData) { if (player != null && this._sendPlayerData) {
this.BroadcastPlayerData(); this.BroadcastPlayerData();
this._sendPlayerData = false; this._sendPlayerData = false;
@ -382,6 +382,8 @@ namespace XIVChatPlugin {
} }
}); });
this._plugin.Events.FireNewClientEvent(id, client);
while (this._clients.TryGetValue(id, out var client) && client.Connected && !client.TokenSource.IsCancellationRequested) { while (this._clients.TryGetValue(id, out var client) && client.Connected && !client.TokenSource.IsCancellationRequested) {
try { try {
var msg = await client.Queue.Reader.ReadAsync(client.TokenSource.Token); var msg = await client.Queue.Reader.ReadAsync(client.TokenSource.Token);
@ -480,7 +482,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.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."); this._plugin.ChatGui.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.");
} }
} }
@ -524,14 +526,13 @@ namespace XIVChatPlugin {
return cached; return cached;
} }
var logKind = this._plugin.Interface.Data.GetExcelSheet<LogKind>().GetRow((ushort) type); var logKind = this._plugin.DataManager.GetExcelSheet<LogKind>()!.GetRow((ushort) type);
if (logKind == null) { if (logKind == null) {
return null; return null;
} }
var format = logKind.Format; var format = (SeString) logKind.Format;
var sestring = this._plugin.Interface.SeStringManager.Parse(format.RawData.ToArray());
static bool IsStringParam(Payload payload, byte num) { static bool IsStringParam(Payload payload, byte num) {
var data = payload.Encode(); var data = payload.Encode();
@ -539,19 +540,19 @@ namespace XIVChatPlugin {
return data.Length >= 5 && data[1] == 0x29 && data[4] == num + 1; return data.Length >= 5 && data[1] == 0x29 && data[4] == num + 1;
} }
var firstStringParam = sestring.Payloads.FindIndex(payload => IsStringParam(payload, 1)); var firstStringParam = format.Payloads.FindIndex(payload => IsStringParam(payload, 1));
var secondStringParam = sestring.Payloads.FindIndex(payload => IsStringParam(payload, 2)); var secondStringParam = format.Payloads.FindIndex(payload => IsStringParam(payload, 2));
if (firstStringParam == -1 || secondStringParam == -1) { if (firstStringParam == -1 || secondStringParam == -1) {
return NameFormatting.Empty(); return NameFormatting.Empty();
} }
var before = sestring.Payloads var before = format.Payloads
.GetRange(0, firstStringParam) .GetRange(0, firstStringParam)
.Where(payload => payload is ITextProvider) .Where(payload => payload is ITextProvider)
.Cast<ITextProvider>() .Cast<ITextProvider>()
.Select(text => text.Text); .Select(text => text.Text);
var after = sestring.Payloads var after = format.Payloads
.GetRange(firstStringParam + 1, secondStringParam - firstStringParam) .GetRange(firstStringParam + 1, secondStringParam - firstStringParam)
.Where(payload => payload is ITextProvider) .Where(payload => payload is ITextProvider)
.Cast<ITextProvider>() .Cast<ITextProvider>()
@ -690,16 +691,16 @@ namespace XIVChatPlugin {
if (input.StartsWith("/")) { if (input.StartsWith("/")) {
var space = input.IndexOf(' '); var space = input.IndexOf(' ');
if (space != -1) { if (space != -1) {
prefix = input.Substring(0, space); prefix = input[..space];
// handle wrapping tells // handle wrapping tells
if (prefix is "/tell" or "/t") { if (prefix is "/tell" or "/t") {
var tellSpace = input.IndexOfCount(' ', 3); var tellSpace = input.IndexOfCount(' ', 3);
if (tellSpace != -1) { if (tellSpace != -1) {
prefix = input.Substring(0, tellSpace); prefix = input[..tellSpace];
input = input.Substring(tellSpace + 1); input = input[(tellSpace + 1)..];
} }
} else { } else {
input = input.Substring(space + 1); input = input[(space + 1)..];
} }
} }
} }
@ -745,7 +746,7 @@ namespace XIVChatPlugin {
_ => 0, _ => 0,
}; };
return this._plugin.Interface.Data.GetExcelSheet<LogFilter>().GetRow(rowId).Name; return this._plugin.DataManager.GetExcelSheet<LogFilter>()!.GetRow(rowId)?.Name ?? string.Empty;
} }
internal void OnChatChannelChange(uint channel) { internal void OnChatChannelChange(uint channel) {
@ -763,16 +764,16 @@ namespace XIVChatPlugin {
} }
private PlayerData? GeneratePlayerData() { private PlayerData? GeneratePlayerData() {
var player = this._plugin.Interface.ClientState.LocalPlayer; var player = this._plugin.ClientState.LocalPlayer;
if (player == null) { if (player == null) {
return null; return null;
} }
var homeWorld = player.HomeWorld.GameData.Name; var homeWorld = player.HomeWorld.GameData.Name;
var currentWorld = player.CurrentWorld.GameData.Name; var currentWorld = player.CurrentWorld.GameData.Name;
var territory = this._plugin.Interface.Data.GetExcelSheet<TerritoryType>().GetRow(this._plugin.Interface.ClientState.TerritoryType); var territory = this._plugin.DataManager.GetExcelSheet<TerritoryType>()!.GetRow(this._plugin.ClientState.TerritoryType);
var location = territory?.PlaceName?.Value?.Name ?? "???"; var location = territory?.PlaceName?.Value?.Name ?? "???";
var name = player.Name; var name = player.Name.TextValue;
return new PlayerData(homeWorld, currentWorld, location, name); return new PlayerData(homeWorld, currentWorld, location, name);
} }
@ -783,18 +784,18 @@ namespace XIVChatPlugin {
this.BroadcastMessage(playerData); this.BroadcastMessage(playerData);
} }
internal 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;
} }
internal void OnLogOut(object sender, EventArgs e) { internal void OnLogOut(object? sender, EventArgs e) {
this.BroadcastAvailability(false); this.BroadcastAvailability(false);
this.BroadcastPlayerData(); this.BroadcastPlayerData();
} }
internal 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
@ -821,7 +822,7 @@ namespace XIVChatPlugin {
internal static class TcpListenerExt { internal static class TcpListenerExt {
internal 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)) { await using (source.Token.Register(listener.Stop)) {
try { try {
var client = await listener.AcceptTcpClientAsync().ConfigureAwait(false); var client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
return client; return client;

View File

@ -2,11 +2,13 @@
<PropertyGroup> <PropertyGroup>
<RootNamespace>XIVChatPlugin</RootNamespace> <RootNamespace>XIVChatPlugin</RootNamespace>
<AssemblyName>XIVChat</AssemblyName> <AssemblyName>XIVChat</AssemblyName>
<TargetFramework>net48</TargetFramework> <TargetFramework>net5-windows</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Version>1.6.0</Version> <Version>1.7.0</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Dalamud"> <Reference Include="Dalamud">
@ -17,10 +19,6 @@
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\ImGui.NET.dll</HintPath> <HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\ImGui.NET.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="ImGuiScene">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\ImGuiScene.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Lumina"> <Reference Include="Lumina">
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.dll</HintPath> <HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.dll</HintPath>
<Private>False</Private> <Private>False</Private>
@ -29,21 +27,25 @@
<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" /> <Reference Include="PeepingTom.Ipc">
<HintPath>..\..\PeepingTom\Peeping Tom.Ipc\bin\Release\net5.0-windows\Peeping Tom.Ipc.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DalamudPackager" Version="1.2.1" /> <PackageReference Include="DalamudPackager" Version="2.1.2"/>
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.18.2" /> <PackageReference Include="MessagePack" Version="2.3.75"/>
<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-netstandard" Version="1.0.1"/>
<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>
<ItemGroup>
<Content Include="Resources\icon.png" Link="images/icon.png" CopyToOutputDirectory="PreserveNewest" Visible="false"/>
</ItemGroup>
</Project> </Project>