mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Better chat injection handling
This commit is contained in:
parent
e75841deb9
commit
ba5fa1f4d0
11 changed files with 207 additions and 72 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup Label="Target">
|
<PropertyGroup Label="Target">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<TargetFramework>net471</TargetFramework>
|
<TargetFramework>net471</TargetFramework>
|
||||||
|
|
@ -14,10 +14,10 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Label="Feature">
|
<PropertyGroup Label="Feature">
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<AssemblyVersion>2.4.0.0</AssemblyVersion>
|
<AssemblyVersion>2.9.0.0</AssemblyVersion>
|
||||||
<FileVersion>2.4.0.0</FileVersion>
|
<FileVersion>2.9.0.0</FileVersion>
|
||||||
<Description>XIVLauncher addon injection</Description>
|
<Description>XIVLauncher addon injection</Description>
|
||||||
<Version>2.4.0</Version>
|
<Version>2.9.0</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="EasyHook" Version="2.7.6270" />
|
<PackageReference Include="EasyHook" Version="2.7.6270" />
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Dalamud.DiscordBot;
|
using Dalamud.DiscordBot;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Game.Chat;
|
using Dalamud.Game.Chat;
|
||||||
|
|
@ -172,6 +174,16 @@ namespace Dalamud {
|
||||||
CommandManager.AddHandler("/xlbotjoin", new CommandInfo(OnBotJoinCommand) {
|
CommandManager.AddHandler("/xlbotjoin", new CommandInfo(OnBotJoinCommand) {
|
||||||
HelpMessage = "Add the XIVLauncher discord bot you set up to your server."
|
HelpMessage = "Add the XIVLauncher discord bot you set up to your server."
|
||||||
});
|
});
|
||||||
|
|
||||||
|
CommandManager.AddHandler("/xlbgmset", new CommandInfo(OnBgmSetCommand)
|
||||||
|
{
|
||||||
|
HelpMessage = "Set the Game background music. Usage: /bgmset <BGM ID>"
|
||||||
|
});
|
||||||
|
|
||||||
|
CommandManager.AddHandler("/xlitem", new CommandInfo(OnItemLinkCommand)
|
||||||
|
{
|
||||||
|
HelpMessage = "Link an item by name. Usage: /item <Item name>"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUnloadCommand(string command, string arguments) {
|
private void OnUnloadCommand(string command, string arguments) {
|
||||||
|
|
@ -198,7 +210,7 @@ namespace Dalamud {
|
||||||
var msg = string.Join(" ", parts.Take(1).ToArray());
|
var msg = string.Join(" ", parts.Take(1).ToArray());
|
||||||
|
|
||||||
Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
||||||
Message = msg,
|
MessageBytes = Encoding.UTF8.GetBytes(msg),
|
||||||
Name = "Xiv Launcher",
|
Name = "Xiv Launcher",
|
||||||
Type = chatType
|
Type = chatType
|
||||||
});
|
});
|
||||||
|
|
@ -419,5 +431,63 @@ namespace Dalamud {
|
||||||
Framework.Gui.Chat.Print(
|
Framework.Gui.Chat.Print(
|
||||||
"The XIVLauncher discord bot was not set up correctly or could not connect to discord. Please check the settings and the FAQ.");
|
"The XIVLauncher discord bot was not set up correctly or could not connect to discord. Please check the settings and the FAQ.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnBgmSetCommand(string command, string arguments)
|
||||||
|
{
|
||||||
|
Framework.Network.InjectBgmTest(int.Parse(arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnItemLinkCommand(string command, string arguments) {
|
||||||
|
Task.Run(async () => {
|
||||||
|
try {
|
||||||
|
dynamic results = await XivApi.Search(arguments, "Item", 1);
|
||||||
|
var itemId = (short) results.Results[0].ID;
|
||||||
|
var itemName = (string)results.Results[0].Name;
|
||||||
|
|
||||||
|
var hexData = new byte[] {
|
||||||
|
0x02, 0x13, 0x06, 0xFE, 0xFF, 0xF3, 0xF3, 0xF3, 0x03, 0x02, 0x27, 0x07, 0x03, 0xF2, 0x3A, 0x2F,
|
||||||
|
0x02, 0x01, 0x03, 0x02, 0x13, 0x06, 0xFE, 0xFF, 0xFF, 0x7B, 0x1A, 0x03, 0xEE, 0x82, 0xBB, 0x02,
|
||||||
|
0x13, 0x02, 0xEC, 0x03
|
||||||
|
};
|
||||||
|
|
||||||
|
var endTag = new byte[] {
|
||||||
|
0x02, 0x27, 0x07, 0xCF, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x03, 0x02, 0x13, 0x02, 0xEC, 0x03
|
||||||
|
};
|
||||||
|
|
||||||
|
BitConverter.GetBytes(itemId).Reverse().ToArray().CopyTo(hexData, 14);
|
||||||
|
|
||||||
|
hexData = hexData.Concat(Encoding.UTF8.GetBytes(itemName)).Concat(endTag).ToArray();
|
||||||
|
|
||||||
|
Framework.Gui.Chat.PrintChat(new XivChatEntry {
|
||||||
|
MessageBytes = hexData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Framework.Gui.Chat.PrintError("Could not find item.");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] StringToByteArray(String value)
|
||||||
|
{
|
||||||
|
byte[] bytes = new byte[value.Length * sizeof(char)];
|
||||||
|
Buffer.BlockCopy(value.ToCharArray(), 0, bytes, 0, bytes.Length);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String ByteArrayToString(byte[] value)
|
||||||
|
{
|
||||||
|
var chars = new char[value.Length / sizeof(char)];
|
||||||
|
|
||||||
|
var atValue = 0;
|
||||||
|
for (var i = 0; i < chars.Length; i++) {
|
||||||
|
chars[i] = BitConverter.ToChar(value, atValue);
|
||||||
|
|
||||||
|
atValue += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string(chars);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Label="Feature">
|
<PropertyGroup Label="Feature">
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<AssemblyVersion>2.5.0.0</AssemblyVersion>
|
<AssemblyVersion>2.7.0.0</AssemblyVersion>
|
||||||
<Version>2.5.0</Version>
|
<Version>2.7.0</Version>
|
||||||
<FileVersion>2.5.0.0</FileVersion>
|
<FileVersion>2.7.0.0</FileVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup Label="Resources">
|
<ItemGroup Label="Resources">
|
||||||
<None Include="$(SolutionDir)/Resources/**/*" CopyToOutputDirectory="PreserveNewest" Visible="false" />
|
<None Include="$(SolutionDir)/Resources/**/*" CopyToOutputDirectory="PreserveNewest" Visible="false" />
|
||||||
|
|
|
||||||
|
|
@ -231,13 +231,13 @@ namespace Dalamud.DiscordBot {
|
||||||
wasOutgoingTell = true;
|
wasOutgoingTell = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var chatTypeConfig =
|
var chatTypeConfigs =
|
||||||
this.config.ChatTypeConfigurations.FirstOrDefault(typeConfig => typeConfig.ChatType == type);
|
this.config.ChatTypeConfigurations.Where(typeConfig => typeConfig.ChatType == type);
|
||||||
|
|
||||||
if (chatTypeConfig == null)
|
if (!chatTypeConfigs.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var channel = await GetChannel(chatTypeConfig.Channel);
|
var channels = chatTypeConfigs.Select(c => GetChannel(c.Channel).GetAwaiter().GetResult());
|
||||||
|
|
||||||
var senderSplit = sender.Split(new[] {this.worldIcon}, StringSplitOptions.None);
|
var senderSplit = sender.Split(new[] {this.worldIcon}, StringSplitOptions.None);
|
||||||
|
|
||||||
|
|
@ -271,8 +271,13 @@ namespace Dalamud.DiscordBot {
|
||||||
Log.Error(ex, "Could not get XIVAPI character search result.");
|
Log.Error(ex, "Could not get XIVAPI character search result.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var embedBuilder = new EmbedBuilder {
|
Thread.Sleep(this.config.ChatDelayMs);
|
||||||
Author = new EmbedAuthorBuilder {
|
|
||||||
|
for (var chatTypeIndex = 0; chatTypeIndex < chatTypeConfigs.Count(); chatTypeIndex++) {
|
||||||
|
var embedBuilder = new EmbedBuilder
|
||||||
|
{
|
||||||
|
Author = new EmbedAuthorBuilder
|
||||||
|
{
|
||||||
IconUrl = avatarUrl,
|
IconUrl = avatarUrl,
|
||||||
Name = wasOutgoingTell
|
Name = wasOutgoingTell
|
||||||
? "You"
|
? "You"
|
||||||
|
|
@ -283,11 +288,12 @@ namespace Dalamud.DiscordBot {
|
||||||
},
|
},
|
||||||
Description = message,
|
Description = message,
|
||||||
Timestamp = DateTimeOffset.Now,
|
Timestamp = DateTimeOffset.Now,
|
||||||
Footer = new EmbedFooterBuilder {Text = type.GetDetails().FancyName},
|
Footer = new EmbedFooterBuilder { Text = type.GetDetails().FancyName },
|
||||||
Color = new Color((uint) (chatTypeConfig.Color & 0xFFFFFF))
|
Color = new Color((uint)(chatTypeConfigs.ElementAt(chatTypeIndex).Color & 0xFFFFFF))
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.config.CheckForDuplicateMessages) {
|
if (this.config.CheckForDuplicateMessages)
|
||||||
|
{
|
||||||
var recentMsg = this.recentMessages.FirstOrDefault(
|
var recentMsg = this.recentMessages.FirstOrDefault(
|
||||||
msg => msg.Embeds.FirstOrDefault(
|
msg => msg.Embeds.FirstOrDefault(
|
||||||
embed => embed.Description == embedBuilder.Description &&
|
embed => embed.Description == embedBuilder.Description &&
|
||||||
|
|
@ -301,17 +307,16 @@ namespace Dalamud.DiscordBot {
|
||||||
.Milliseconds) < 15000)
|
.Milliseconds) < 15000)
|
||||||
!= null);
|
!= null);
|
||||||
|
|
||||||
if (recentMsg != null) {
|
if (recentMsg != null)
|
||||||
|
{
|
||||||
Log.Verbose("Duplicate message: [{0}] {1}", embedBuilder.Author.Name, embedBuilder.Description);
|
Log.Verbose("Duplicate message: [{0}] {1}", embedBuilder.Author.Name, embedBuilder.Description);
|
||||||
this.recentMessages.Remove(recentMsg);
|
this.recentMessages.Remove(recentMsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await channels.ElementAt(chatTypeIndex).SendMessageAsync(embed: embedBuilder.Build());
|
||||||
Thread.Sleep(this.config.ChatDelayMs);
|
}
|
||||||
|
|
||||||
await channel.SendMessageAsync(embed: embedBuilder.Build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IMessageChannel> GetChannel(ChannelConfiguration channelConfig) {
|
private async Task<IMessageChannel> GetChannel(ChannelConfiguration channelConfig) {
|
||||||
|
|
@ -321,7 +326,7 @@ namespace Dalamud.DiscordBot {
|
||||||
}
|
}
|
||||||
|
|
||||||
private string RemoveAllNonLanguageCharacters(string input) {
|
private string RemoveAllNonLanguageCharacters(string input) {
|
||||||
return Regex.Replace(input, @"[^\p{L} ]", "");
|
return Regex.Replace(input, @"[^\p{L} ']", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace Dalamud.Game.Chat {
|
||||||
|
|
||||||
public string Name { get; set; } = string.Empty;
|
public string Name { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string Message { get; set; } = string.Empty;
|
public byte[] MessageBytes { get; set; }
|
||||||
|
|
||||||
public IntPtr Parameters { get; set; }
|
public IntPtr Parameters { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -67,7 +69,7 @@ namespace Dalamud.Game {
|
||||||
ref bool isHandled) {
|
ref bool isHandled) {
|
||||||
|
|
||||||
if (type == XivChatType.Notice && !this.hasSeenLoadingMsg) {
|
if (type == XivChatType.Notice && !this.hasSeenLoadingMsg) {
|
||||||
this.dalamud.Framework.Gui.Chat.Print("XIVLauncher in-game addon loaded.");
|
this.dalamud.Framework.Gui.Chat.Print($"XIVLauncher in-game addon v{Assembly.GetAssembly(typeof(ChatHandlers)).GetName().Version} loaded.");
|
||||||
this.hasSeenLoadingMsg = true;
|
this.hasSeenLoadingMsg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,16 +42,21 @@ namespace Dalamud.Game.ClientState.Actors {
|
||||||
if (offset == IntPtr.Zero)
|
if (offset == IntPtr.Zero)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
try {
|
||||||
var actorStruct = Marshal.PtrToStructure<Structs.Actor>(offset);
|
var actorStruct = Marshal.PtrToStructure<Structs.Actor>(offset);
|
||||||
|
|
||||||
//Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"),
|
//Log.Debug("ActorTable[{0}]: {1} - {2} - {3}", index, tblIndex.ToString("X"), offset.ToString("X"),
|
||||||
// actorStruct.ObjectKind.ToString());
|
// actorStruct.ObjectKind.ToString());
|
||||||
|
|
||||||
switch (actorStruct.ObjectKind) {
|
switch (actorStruct.ObjectKind)
|
||||||
|
{
|
||||||
case ObjectKind.Player: return new PlayerCharacter(actorStruct);
|
case ObjectKind.Player: return new PlayerCharacter(actorStruct);
|
||||||
case ObjectKind.BattleNpc: return new BattleNpc(actorStruct);
|
case ObjectKind.BattleNpc: return new BattleNpc(actorStruct);
|
||||||
default: return new Actor(actorStruct);
|
default: return new Actor(actorStruct);
|
||||||
}
|
}
|
||||||
|
} catch (AccessViolationException) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ namespace Dalamud.Game.Internal {
|
||||||
private bool HandleFrameworkUpdate(IntPtr framework) {
|
private bool HandleFrameworkUpdate(IntPtr framework) {
|
||||||
try {
|
try {
|
||||||
Gui.Chat.UpdateQueue(this);
|
Gui.Chat.UpdateQueue(this);
|
||||||
|
Network.UpdateQueue(this);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Log.Error(ex, "Exception while handling Framework::Update hook.");
|
Log.Error(ex, "Exception while handling Framework::Update hook.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
using Dalamud.Game.Chat;
|
using Dalamud.Game.Chat;
|
||||||
using Dalamud.Game.Internal.Libc;
|
using Dalamud.Game.Internal.Libc;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
|
|
@ -11,7 +12,7 @@ namespace Dalamud.Game.Internal.Gui {
|
||||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||||
private delegate void PrintMessageDelegate(IntPtr manager, XivChatType chatType, IntPtr senderName,
|
private delegate void PrintMessageDelegate(IntPtr manager, XivChatType chatType, IntPtr senderName,
|
||||||
IntPtr message,
|
IntPtr message,
|
||||||
uint senderId, byte isLocal);
|
uint senderId, IntPtr parameter);
|
||||||
|
|
||||||
public delegate void OnMessageDelegate(XivChatType type, uint senderId, string sender, ref string message,
|
public delegate void OnMessageDelegate(XivChatType type, uint senderId, string sender, ref string message,
|
||||||
ref bool isHandled);
|
ref bool isHandled);
|
||||||
|
|
@ -79,12 +80,12 @@ namespace Dalamud.Game.Internal.Gui {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandlePrintMessageDetour(IntPtr manager, XivChatType chattype, IntPtr pSenderName, IntPtr pMessage,
|
private void HandlePrintMessageDetour(IntPtr manager, XivChatType chattype, IntPtr pSenderName, IntPtr pMessage,
|
||||||
uint senderid, byte isLocal) {
|
uint senderid, IntPtr parameter) {
|
||||||
try {
|
try {
|
||||||
var senderName = StdString.ReadFromPointer(pSenderName);
|
var senderName = StdString.ReadFromPointer(pSenderName);
|
||||||
var message = StdString.ReadFromPointer(pMessage);
|
var message = StdString.ReadFromPointer(pMessage);
|
||||||
|
|
||||||
//Log.Debug($"HandlePrintMessageDetour {manager} - [{chattype}] [{BitConverter.ToString(Encoding.UTF8.GetBytes(message))}] {message} from {senderName}");
|
Log.Debug($"HandlePrintMessageDetour {manager} - [{chattype}] [{BitConverter.ToString(Encoding.UTF8.GetBytes(message)).Replace("-", " ")}] {message} from {senderName}");
|
||||||
|
|
||||||
var originalMessage = string.Copy(message);
|
var originalMessage = string.Copy(message);
|
||||||
|
|
||||||
|
|
@ -96,7 +97,7 @@ namespace Dalamud.Game.Internal.Gui {
|
||||||
OwnedStdString allocatedString = null;
|
OwnedStdString allocatedString = null;
|
||||||
|
|
||||||
if (originalMessage != message) {
|
if (originalMessage != message) {
|
||||||
allocatedString = this.dalamud.Framework.Libc.NewString(message);
|
allocatedString = this.dalamud.Framework.Libc.NewString(Encoding.UTF8.GetBytes(message));
|
||||||
Log.Debug(
|
Log.Debug(
|
||||||
$"HandlePrintMessageDetour String modified: {originalMessage}({messagePtr}) -> {message}({allocatedString.Address})");
|
$"HandlePrintMessageDetour String modified: {originalMessage}({messagePtr}) -> {message}({allocatedString.Address})");
|
||||||
messagePtr = allocatedString.Address;
|
messagePtr = allocatedString.Address;
|
||||||
|
|
@ -104,7 +105,7 @@ namespace Dalamud.Game.Internal.Gui {
|
||||||
|
|
||||||
// Print the original chat if it's handled.
|
// Print the original chat if it's handled.
|
||||||
if (!isHandled)
|
if (!isHandled)
|
||||||
this.printMessageHook.Original(manager, chattype, pSenderName, messagePtr, senderid, isLocal);
|
this.printMessageHook.Original(manager, chattype, pSenderName, messagePtr, senderid, parameter);
|
||||||
|
|
||||||
if (this.baseAddress == IntPtr.Zero)
|
if (this.baseAddress == IntPtr.Zero)
|
||||||
this.baseAddress = manager;
|
this.baseAddress = manager;
|
||||||
|
|
@ -112,7 +113,7 @@ namespace Dalamud.Game.Internal.Gui {
|
||||||
allocatedString?.Dispose();
|
allocatedString?.Dispose();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Log.Error(ex, "Exception on OnChatMessage hook.");
|
Log.Error(ex, "Exception on OnChatMessage hook.");
|
||||||
this.printMessageHook.Original(manager, chattype, pSenderName, pMessage, senderid, isLocal);
|
this.printMessageHook.Original(manager, chattype, pSenderName, pMessage, senderid, parameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,13 +128,13 @@ namespace Dalamud.Game.Internal.Gui {
|
||||||
|
|
||||||
public void Print(string message) {
|
public void Print(string message) {
|
||||||
PrintChat(new XivChatEntry {
|
PrintChat(new XivChatEntry {
|
||||||
Message = message
|
MessageBytes = Encoding.UTF8.GetBytes(message)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PrintError(string message) {
|
public void PrintError(string message) {
|
||||||
PrintChat(new XivChatEntry {
|
PrintChat(new XivChatEntry {
|
||||||
Message = message,
|
MessageBytes = Encoding.UTF8.GetBytes(message),
|
||||||
Type = XivChatType.Urgent
|
Type = XivChatType.Urgent
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -146,13 +147,15 @@ namespace Dalamud.Game.Internal.Gui {
|
||||||
var chat = this.chatQueue.Dequeue();
|
var chat = this.chatQueue.Dequeue();
|
||||||
|
|
||||||
var sender = chat.Name ?? "";
|
var sender = chat.Name ?? "";
|
||||||
var message = chat.Message ?? "";
|
var message = chat.MessageBytes ?? new byte[0];
|
||||||
|
|
||||||
if (this.baseAddress != IntPtr.Zero)
|
if (this.baseAddress != IntPtr.Zero)
|
||||||
using (var senderVec = framework.Libc.NewString(sender))
|
using (var senderVec = framework.Libc.NewString(Encoding.UTF8.GetBytes(sender)))
|
||||||
using (var messageVec = framework.Libc.NewString(message)) {
|
using (var messageVec = framework.Libc.NewString(message))
|
||||||
|
{
|
||||||
|
Log.Verbose($"String allocated to {messageVec.Address.ToInt64():X}");
|
||||||
this.printMessageHook.Original(this.baseAddress, chat.Type, senderVec.Address,
|
this.printMessageHook.Original(this.baseAddress, chat.Type, senderVec.Address,
|
||||||
messageVec.Address, chat.SenderId, 0);
|
messageVec.Address, chat.SenderId, chat.Parameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
|
|
@ -6,7 +6,7 @@ namespace Dalamud.Game.Internal.Libc {
|
||||||
public sealed class LibcFunction {
|
public sealed class LibcFunction {
|
||||||
// TODO: prolly callconv is not okay in x86
|
// TODO: prolly callconv is not okay in x86
|
||||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||||
private delegate IntPtr StdStringFromCStringDelegate(IntPtr pStdString, [MarshalAs(UnmanagedType.LPUTF8Str)]string content, IntPtr size);
|
private delegate IntPtr StdStringFromCStringDelegate(IntPtr pStdString, [MarshalAs(UnmanagedType.LPArray)]byte[] content, IntPtr size);
|
||||||
|
|
||||||
// TODO: prolly callconv is not okay in x86
|
// TODO: prolly callconv is not okay in x86
|
||||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Dalamud.Game.Internal.Libc {
|
||||||
this.stdStringDeallocate = Marshal.GetDelegateForFunctionPointer<StdStringDeallocateDelegate>(Address.StdStringDeallocate);
|
this.stdStringDeallocate = Marshal.GetDelegateForFunctionPointer<StdStringDeallocateDelegate>(Address.StdStringDeallocate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public OwnedStdString NewString(string content) {
|
public OwnedStdString NewString(byte[] content) {
|
||||||
Log.Verbose("Allocating");
|
Log.Verbose("Allocating");
|
||||||
|
|
||||||
// While 0x70 bytes in the memory should be enough in DX11 version,
|
// While 0x70 bytes in the memory should be enough in DX11 version,
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Dalamud.Game.Internal.Libc {
|
||||||
var npos = new IntPtr(0xFFFFFFFF); // assumed to be -1 (0xFFFFFFFF in x86, 0xFFFFFFFF_FFFFFFFF in amd64)
|
var npos = new IntPtr(0xFFFFFFFF); // assumed to be -1 (0xFFFFFFFF in x86, 0xFFFFFFFF_FFFFFFFF in amd64)
|
||||||
var pReallocString = this.stdStringCtorCString(pString, content, npos);
|
var pReallocString = this.stdStringCtorCString(pString, content, npos);
|
||||||
|
|
||||||
Log.Verbose("Prev: {Prev} Now: {Now}", pString, pReallocString);
|
//Log.Verbose("Prev: {Prev} Now: {Now}", pString, pReallocString);
|
||||||
|
|
||||||
return new OwnedStdString(pReallocString, DeallocateStdString);
|
return new OwnedStdString(pReallocString, DeallocateStdString);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
@ -11,6 +13,7 @@ namespace Dalamud.Game.Internal.Network {
|
||||||
private readonly Hook<ProcessZonePacketDelegate> processZonePacketHook;
|
private readonly Hook<ProcessZonePacketDelegate> processZonePacketHook;
|
||||||
|
|
||||||
private GameNetworkAddressResolver Address { get; }
|
private GameNetworkAddressResolver Address { get; }
|
||||||
|
private IntPtr baseAddress;
|
||||||
|
|
||||||
public delegate void OnZonePacketDelegate(IntPtr dataPtr);
|
public delegate void OnZonePacketDelegate(IntPtr dataPtr);
|
||||||
|
|
||||||
|
|
@ -18,6 +21,8 @@ namespace Dalamud.Game.Internal.Network {
|
||||||
|
|
||||||
private readonly Dalamud dalamud;
|
private readonly Dalamud dalamud;
|
||||||
|
|
||||||
|
private readonly Queue<byte[]> zoneInjectQueue = new Queue<byte[]>();
|
||||||
|
|
||||||
public GameNetwork(Dalamud dalamud, SigScanner scanner) {
|
public GameNetwork(Dalamud dalamud, SigScanner scanner) {
|
||||||
this.dalamud = dalamud;
|
this.dalamud = dalamud;
|
||||||
Address = new GameNetworkAddressResolver();
|
Address = new GameNetworkAddressResolver();
|
||||||
|
|
@ -40,6 +45,8 @@ namespace Dalamud.Game.Internal.Network {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessZonePacketDetour(IntPtr a, IntPtr b, IntPtr dataPtr) {
|
private void ProcessZonePacketDetour(IntPtr a, IntPtr b, IntPtr dataPtr) {
|
||||||
|
this.baseAddress = a;
|
||||||
|
|
||||||
// Call events
|
// Call events
|
||||||
this.OnZonePacket?.Invoke(dataPtr);
|
this.OnZonePacket?.Invoke(dataPtr);
|
||||||
|
|
||||||
|
|
@ -60,5 +67,47 @@ namespace Dalamud.Game.Internal.Network {
|
||||||
this.processZonePacketHook.Original(a, b, dataPtr);
|
this.processZonePacketHook.Original(a, b, dataPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InjectZoneProtoPacket(byte[] data) {
|
||||||
|
this.zoneInjectQueue.Enqueue(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InjectActorControl(short cat, int param1) {
|
||||||
|
var packetData = new byte[] {
|
||||||
|
0x14, 0x00, 0x64, 0x01, 0x00, 0x00, 0x0E, 0x00, 0x17, 0x7C, 0xC5, 0x5D, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x05, 0x00, 0x48, 0xB2, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x43, 0x7F, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
BitConverter.GetBytes((short) cat).CopyTo(packetData, 0x10);
|
||||||
|
|
||||||
|
BitConverter.GetBytes((UInt32) param1).CopyTo(packetData, 0x14);
|
||||||
|
|
||||||
|
InjectZoneProtoPacket(packetData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InjectBgmTest(int key) {
|
||||||
|
InjectActorControl(0xa1, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process a chat queue.
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateQueue(Framework framework)
|
||||||
|
{
|
||||||
|
while (this.zoneInjectQueue.Count > 0)
|
||||||
|
{
|
||||||
|
var packetData = this.zoneInjectQueue.Dequeue();
|
||||||
|
|
||||||
|
var unmanagedPacketData = Marshal.AllocHGlobal(packetData.Length);
|
||||||
|
Marshal.Copy(packetData, 0, unmanagedPacketData, packetData.Length);
|
||||||
|
|
||||||
|
if (this.baseAddress != IntPtr.Zero) {
|
||||||
|
this.processZonePacketHook.Original(this.baseAddress, IntPtr.Zero, unmanagedPacketData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Marshal.FreeHGlobal(unmanagedPacketData);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue