Compare commits
2 Commits
9d7b099b14
...
b9516b2b1a
Author | SHA1 | Date |
---|---|---|
Anna | b9516b2b1a | |
Anna | e9a250bf57 |
File diff suppressed because it is too large
Load Diff
|
@ -16,63 +16,63 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\fonticon_ps4.tex.png"/>
|
||||
<None Remove="Resources\fonts\ffxiv.ttf"/>
|
||||
<None Remove="Resources\logo.ico"/>
|
||||
<None Remove="Resources\status\app_status_afk.png"/>
|
||||
<None Remove="Resources\status\app_status_contents.png"/>
|
||||
<None Remove="Resources\status\app_status_contents_same.png"/>
|
||||
<None Remove="Resources\status\app_status_contents_similar.png"/>
|
||||
<None Remove="Resources\status\app_status_cross_party_leader.png"/>
|
||||
<None Remove="Resources\status\app_status_cross_party_member.png"/>
|
||||
<None Remove="Resources\status\app_status_offline.png"/>
|
||||
<None Remove="Resources\status\app_status_online.png"/>
|
||||
<None Remove="Resources\status\app_status_party_leader.png"/>
|
||||
<None Remove="Resources\status\app_status_party_member.png"/>
|
||||
<None Remove="Resources\status\app_status_roleplaying.png"/>
|
||||
<None Remove="Resources\status\app_status_roleplaying.svg"/>
|
||||
<None Remove="Resources\fonticon_ps4.tex.png" />
|
||||
<None Remove="Resources\fonts\ffxiv.ttf" />
|
||||
<None Remove="Resources\logo.ico" />
|
||||
<None Remove="Resources\status\app_status_afk.png" />
|
||||
<None Remove="Resources\status\app_status_contents.png" />
|
||||
<None Remove="Resources\status\app_status_contents_same.png" />
|
||||
<None Remove="Resources\status\app_status_contents_similar.png" />
|
||||
<None Remove="Resources\status\app_status_cross_party_leader.png" />
|
||||
<None Remove="Resources\status\app_status_cross_party_member.png" />
|
||||
<None Remove="Resources\status\app_status_offline.png" />
|
||||
<None Remove="Resources\status\app_status_online.png" />
|
||||
<None Remove="Resources\status\app_status_party_leader.png" />
|
||||
<None Remove="Resources\status\app_status_party_member.png" />
|
||||
<None Remove="Resources\status\app_status_roleplaying.png" />
|
||||
<None Remove="Resources\status\app_status_roleplaying.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\fonticon_ps4.tex.png"/>
|
||||
<Resource Include="Resources\fonts\ffxiv.ttf"/>
|
||||
<Resource Include="Resources\logo.ico"/>
|
||||
<Resource Include="Resources\status\app_status_afk.png"/>
|
||||
<Resource Include="Resources\status\app_status_contents.png"/>
|
||||
<Resource Include="Resources\status\app_status_contents_same.png"/>
|
||||
<Resource Include="Resources\status\app_status_contents_similar.png"/>
|
||||
<Resource Include="Resources\status\app_status_cross_party_leader.png"/>
|
||||
<Resource Include="Resources\status\app_status_cross_party_member.png"/>
|
||||
<Resource Include="Resources\status\app_status_offline.png"/>
|
||||
<Resource Include="Resources\status\app_status_online.png"/>
|
||||
<Resource Include="Resources\status\app_status_party_leader.png"/>
|
||||
<Resource Include="Resources\status\app_status_party_member.png"/>
|
||||
<Resource Include="Resources\status\app_status_roleplaying.png"/>
|
||||
<Resource Include="Resources\fonticon_ps4.tex.png" />
|
||||
<Resource Include="Resources\fonts\ffxiv.ttf" />
|
||||
<Resource Include="Resources\logo.ico" />
|
||||
<Resource Include="Resources\status\app_status_afk.png" />
|
||||
<Resource Include="Resources\status\app_status_contents.png" />
|
||||
<Resource Include="Resources\status\app_status_contents_same.png" />
|
||||
<Resource Include="Resources\status\app_status_contents_similar.png" />
|
||||
<Resource Include="Resources\status\app_status_cross_party_leader.png" />
|
||||
<Resource Include="Resources\status\app_status_cross_party_member.png" />
|
||||
<Resource Include="Resources\status\app_status_offline.png" />
|
||||
<Resource Include="Resources\status\app_status_online.png" />
|
||||
<Resource Include="Resources\status\app_status_party_leader.png" />
|
||||
<Resource Include="Resources\status\app_status_party_member.png" />
|
||||
<Resource Include="Resources\status\app_status_roleplaying.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autoupdater.NET.Official" Version="1.6.4"/>
|
||||
<PackageReference Include="Fody" Version="6.5.1">
|
||||
<PackageReference Include="Autoupdater.NET.Official" Version="1.7.0" />
|
||||
<PackageReference Include="Fody" Version="6.6.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0"/>
|
||||
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.0.2"/>
|
||||
<PackageReference Include="ModernWpfUI" Version="0.9.4"/>
|
||||
<PackageReference Include="ModernWpfUI.MahApps" Version="0.9.4"/>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
|
||||
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
|
||||
<PackageReference Include="ModernWpfUI" Version="0.9.4" />
|
||||
<PackageReference Include="ModernWpfUI.MahApps" Version="0.9.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Sentry" Version="3.4.0"/>
|
||||
<PackageReference Include="Sodium.Core" Version="1.2.3"/>
|
||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2"/>
|
||||
<PackageReference Include="WpfWindowPlacement" Version="3.0.0"/>
|
||||
<PackageReference Include="Sentry" Version="3.16.0" />
|
||||
<PackageReference Include="Sodium.Core" Version="1.2.3" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
|
||||
<PackageReference Include="WpfWindowPlacement" Version="3.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MdXaml\MdXaml\MdXaml.csproj"/>
|
||||
<ProjectReference Include="..\XIVChatCommon\XIVChatCommon.csproj"/>
|
||||
<ProjectReference Include="..\MdXaml\MdXaml\MdXaml.csproj" />
|
||||
<ProjectReference Include="..\XIVChatCommon\XIVChatCommon.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -26,6 +26,9 @@ namespace XIVChatCommon.Message.Client {
|
|||
|
||||
[Preference(typeof(bool))]
|
||||
TargetingListSupport = 1,
|
||||
|
||||
[Preference(typeof(bool))]
|
||||
HousingLocationSupport = 2,
|
||||
}
|
||||
|
||||
public static class ClientPreferencesExtension {
|
||||
|
|
|
@ -33,4 +33,4 @@ namespace XIVChatCommon.Message.Server {
|
|||
return MessagePackSerializer.Serialize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,14 @@ namespace XIVChatCommon.Message.Server {
|
|||
[Key(0)]
|
||||
public readonly ServerMessage[] messages;
|
||||
|
||||
[Key(1)]
|
||||
public readonly uint sequence;
|
||||
|
||||
protected override byte Code => (byte)ServerOperation.Backlog;
|
||||
|
||||
public ServerBacklog(ServerMessage[] messages) {
|
||||
public ServerBacklog(ServerMessage[] messages, uint sequence) {
|
||||
this.messages = messages;
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
public static ServerBacklog Decode(byte[] bytes) {
|
||||
|
@ -20,4 +24,4 @@ namespace XIVChatCommon.Message.Server {
|
|||
return MessagePackSerializer.Serialize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
using MessagePack;
|
||||
|
||||
namespace XIVChatCommon.Message.Server {
|
||||
[MessagePackObject]
|
||||
public class ServerHousingLocation : Encodable {
|
||||
[Key(0)]
|
||||
public readonly ushort? ward;
|
||||
|
||||
[Key(1)]
|
||||
public readonly ushort? plot;
|
||||
|
||||
[Key(2)]
|
||||
public readonly bool plotExterior;
|
||||
|
||||
[Key(3)]
|
||||
public readonly byte? apartmentWing;
|
||||
|
||||
public ServerHousingLocation(ushort? ward, ushort? plot, bool plotExterior, byte? apartmentWing) {
|
||||
this.ward = ward;
|
||||
this.plot = plot;
|
||||
this.plotExterior = plotExterior;
|
||||
this.apartmentWing = apartmentWing;
|
||||
}
|
||||
|
||||
[IgnoreMember]
|
||||
protected override byte Code => (byte) ServerOperation.HousingLocation;
|
||||
|
||||
public static ServerHousingLocation Decode(byte[] bytes) {
|
||||
return MessagePackSerializer.Deserialize<ServerHousingLocation>(bytes);
|
||||
}
|
||||
|
||||
protected override byte[] PayloadEncode() {
|
||||
return MessagePackSerializer.Serialize(this);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj) {
|
||||
if (obj is not ServerHousingLocation other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.ward == other.ward
|
||||
&& this.plot == other.plot
|
||||
&& this.plotExterior == other.plotExterior
|
||||
&& this.apartmentWing == other.apartmentWing;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
unchecked {
|
||||
var hashCode = this.ward.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ this.plot.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ this.plotExterior.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ this.apartmentWing.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,6 @@
|
|||
Backlog = 7,
|
||||
PlayerList = 8,
|
||||
LinkshellList = 9,
|
||||
TargetingList = 10,
|
||||
HousingLocation = 10,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
<Nullable>enable</Nullable>
|
||||
<AssemblyVersion>1.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0</FileVersion>
|
||||
<TargetFrameworks>net48;net5.0</TargetFrameworks>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MessagePack" Version="2.2.85"/>
|
||||
<PackageReference Include="MessagePack" Version="2.3.85"/>
|
||||
<PackageReference Include="Sodium.Core" Version="1.2.3"/>
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -8,14 +8,14 @@ using System.Runtime.InteropServices;
|
|||
using System.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Memory;
|
||||
using Siggingway;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||
using XIVChatCommon.Message;
|
||||
using XIVChatCommon.Message.Server;
|
||||
|
||||
namespace XIVChatPlugin {
|
||||
internal class GameFunctions : IDisposable {
|
||||
internal unsafe class GameFunctions : IDisposable {
|
||||
private static class Signatures {
|
||||
internal const string GetUiModule = "E8 ?? ?? ?? ?? 48 83 7F ?? 00 48 8B F0";
|
||||
internal const string ProcessChat = "48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 45 84 C9";
|
||||
internal const string Input = "80 B9 ?? ?? ?? ?? ?? 0F 9C C0";
|
||||
internal const string InputAfk = "E8 ?? ?? ?? ?? 0F 28 74 24 ?? 0F B6 F0";
|
||||
|
@ -30,8 +30,6 @@ namespace XIVChatPlugin {
|
|||
internal const string ChannelNameChange = "E8 ?? ?? ?? ?? BA ?? ?? ?? ?? 48 8D 4D B0 48 8B F8 E8 ?? ?? ?? ?? 41 8B D6";
|
||||
internal const string XivStringCtor = "E8 ?? ?? ?? ?? 44 2B F7";
|
||||
internal const string XivStringDtor = "E8 ?? ?? ?? ?? B0 6E";
|
||||
internal const string UiModule = "48 8B 0D ?? ?? ?? ?? 48 8D 54 24 ?? 48 83 C1 10 E8";
|
||||
internal const string ColourHandler = "48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 85 C9 0F 84 ?? ?? ?? ?? 66 85 DB 0F 94 C2 E8 ?? ?? ?? ?? E9";
|
||||
internal const string ColourLookup = "48 8D 0D ?? ?? ?? ?? 8B 14 ?? 85 D2 7E ?? 48 8B 0D ?? ?? ?? ?? 48 83 C1 10 E8 ?? ?? ?? ?? 8B 70 ?? 41 8D 4D";
|
||||
}
|
||||
|
||||
|
@ -39,8 +37,6 @@ namespace XIVChatPlugin {
|
|||
|
||||
#region Delegates
|
||||
|
||||
private delegate IntPtr GetUiModuleDelegate(IntPtr basePtr);
|
||||
|
||||
private delegate void EasierProcessChatBoxDelegate(IntPtr uiModule, IntPtr message, IntPtr unused, byte a4);
|
||||
|
||||
private delegate byte IsInputDelegate(IntPtr a1);
|
||||
|
@ -94,9 +90,6 @@ namespace XIVChatPlugin {
|
|||
|
||||
#region Functions
|
||||
|
||||
[Signature(Signatures.GetUiModule)]
|
||||
private readonly GetUiModuleDelegate? _getUiModule;
|
||||
|
||||
[Signature(Signatures.ProcessChat)]
|
||||
private readonly EasierProcessChatBoxDelegate? _easierProcessChatBox;
|
||||
|
||||
|
@ -116,12 +109,6 @@ namespace XIVChatPlugin {
|
|||
|
||||
#region Pointers
|
||||
|
||||
[Signature(Signatures.UiModule, ScanType = ScanType.StaticAddress)]
|
||||
private IntPtr UiModulePtr { get; init; }
|
||||
|
||||
[Signature(Signatures.ColourHandler, ScanType = ScanType.StaticAddress)]
|
||||
private IntPtr ColourHandler { get; init; }
|
||||
|
||||
[Signature(Signatures.ColourLookup, ScanType = ScanType.StaticAddress)]
|
||||
private IntPtr ColourLookup { get; init; }
|
||||
|
||||
|
@ -165,6 +152,8 @@ namespace XIVChatPlugin {
|
|||
|
||||
internal GameFunctions(Plugin plugin) {
|
||||
this.Plugin = plugin;
|
||||
|
||||
SignatureHelper.Initialise(this);
|
||||
|
||||
this._friendListHook?.Enable();
|
||||
this._formatHook?.Enable();
|
||||
|
@ -210,7 +199,7 @@ namespace XIVChatPlugin {
|
|||
//
|
||||
// If this function would ever return 0, it returns null instead.
|
||||
internal uint? GetChannelColour(ChatCode channel) {
|
||||
if (this._getColourInfo == null || this.ColourLookup == IntPtr.Zero || this.ColourHandler == IntPtr.Zero) {
|
||||
if (this._getColourInfo == null || this.ColourLookup == IntPtr.Zero) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -228,9 +217,11 @@ 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 framework = (IntPtr) Framework.Instance();
|
||||
|
||||
var lookupResult = *(uint*) (this.ColourLookup + (int) parent * 4);
|
||||
var info = this._getColourInfo(framework + 16, lookupResult);
|
||||
var rgb = *(uint*) (info + 32) & 0xFFFFFF;
|
||||
|
||||
if (rgb == 0) {
|
||||
return null;
|
||||
|
@ -240,23 +231,19 @@ namespace XIVChatPlugin {
|
|||
}
|
||||
|
||||
internal void ProcessChatBox(string message) {
|
||||
if (this._easierProcessChatBox == null || this._getUiModule == null || this.UiModulePtr == IntPtr.Zero) {
|
||||
if (this._easierProcessChatBox == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.HadInput = InputSetters.Normal | InputSetters.Afk;
|
||||
|
||||
var uiModule = this._getUiModule(Marshal.ReadIntPtr(this.UiModulePtr));
|
||||
|
||||
if (uiModule == IntPtr.Zero) {
|
||||
throw new ArgumentException("pointer was null", nameof(uiModule));
|
||||
}
|
||||
var uiModule = Framework.Instance()->GetUiModule();
|
||||
|
||||
using var payload = new ChatPayload(message);
|
||||
var mem1 = Marshal.AllocHGlobal(400);
|
||||
Marshal.StructureToPtr(payload, mem1, false);
|
||||
|
||||
this._easierProcessChatBox(uiModule, mem1, IntPtr.Zero, 0);
|
||||
this._easierProcessChatBox((IntPtr) uiModule, mem1, IntPtr.Zero, 0);
|
||||
|
||||
Marshal.FreeHGlobal(mem1);
|
||||
}
|
||||
|
@ -278,7 +265,7 @@ namespace XIVChatPlugin {
|
|||
return this._chatChannelChangeHook!.Original(a1, channel);
|
||||
}
|
||||
|
||||
private unsafe IntPtr ChangeChatChannelNameDetour(IntPtr a1) {
|
||||
private IntPtr ChangeChatChannelNameDetour(IntPtr a1) {
|
||||
// Last ShB patch
|
||||
// +0x40 = chat channel (byte or uint?)
|
||||
// channel is 17 (maybe 18?) for tells
|
||||
|
@ -385,7 +372,7 @@ namespace XIVChatPlugin {
|
|||
goto Return;
|
||||
}
|
||||
|
||||
if (Marshal.ReadByte(data + 0xc) != 2 || Marshal.ReadInt16(data + 0x8) != 0) {
|
||||
if (*(byte*) (data + 0xc) != 2 || *(ushort*) (data + 0x8) != 0) {
|
||||
goto Return;
|
||||
}
|
||||
|
||||
|
@ -429,7 +416,7 @@ namespace XIVChatPlugin {
|
|||
private readonly ulong unk2;
|
||||
|
||||
internal ChatPayload(string text) {
|
||||
byte[] stringBytes = Encoding.UTF8.GetBytes(text);
|
||||
var stringBytes = Encoding.UTF8.GetBytes(text);
|
||||
this.textPtr = Marshal.AllocHGlobal(stringBytes.Length + 30);
|
||||
Marshal.Copy(stringBytes, 0, this.textPtr, stringBytes.Length);
|
||||
Marshal.WriteByte(this.textPtr + stringBytes.Length, 0);
|
||||
|
@ -473,7 +460,7 @@ namespace XIVChatPlugin {
|
|||
private readonly byte[] fc;
|
||||
|
||||
private static string? HandleString(IEnumerable<byte> bytes) {
|
||||
byte[] nonNull = bytes.TakeWhile(b => b != 0).ToArray();
|
||||
var nonNull = bytes.TakeWhile(b => b != 0).ToArray();
|
||||
return nonNull.Length == 0 ? null : Encoding.UTF8.GetString(nonNull);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace XIVChatPlugin {
|
|||
}
|
||||
|
||||
// PluginLog.Log($"start: {start.ToInt64():x}");
|
||||
|
||||
|
||||
foreach (var offset in offsets) {
|
||||
start = Marshal.ReadIntPtr(start + offset);
|
||||
// PluginLog.Log($" + {offset}: {start.ToInt64():x}");
|
||||
|
|
|
@ -5,16 +5,22 @@
|
|||
<TargetFramework>net5-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Version>1.7.1</Version>
|
||||
<Version>1.7.2</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Dalamud">
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Dalamud.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="FFXIVClientStructs">
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\FFXIVClientStructs.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGui.NET">
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\ImGui.NET.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
|
@ -33,13 +39,12 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DalamudLinter" Version="1.0.3"/>
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.5"/>
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.6"/>
|
||||
<PackageReference Include="MessagePack" Version="2.3.85"/>
|
||||
<PackageReference Include="Siggingway" Version="1.1.0"/>
|
||||
<PackageReference Include="Sodium.Core" Version="1.2.3"/>
|
||||
<PackageReference Include="System.Threading.Channels" Version="6.0.0"/>
|
||||
<PackageReference Include="WebSocketSharp-netstandard" Version="1.0.1"/>
|
||||
<PackageReference Include="XivCommon" Version="4.0.0"/>
|
||||
<PackageReference Include="XivCommon" Version="5.0.1-alpha.1"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\XIVChatCommon\XIVChatCommon.csproj"/>
|
||||
|
|
Loading…
Reference in New Issue