mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-14 12:44:16 +01:00
Refactor chat handling
This commit is contained in:
parent
397816ef7b
commit
c1aeaceb47
5 changed files with 57 additions and 54 deletions
|
|
@ -7,6 +7,7 @@ using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Dalamud.Game.Chat;
|
using Dalamud.Game.Chat;
|
||||||
|
using Dalamud.Game.Internal.Libc;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Dalamud.Game {
|
namespace Dalamud.Game {
|
||||||
|
|
@ -93,8 +94,8 @@ namespace Dalamud.Game {
|
||||||
|
|
||||||
public string LastLink { get; private set; }
|
public string LastLink { get; private set; }
|
||||||
|
|
||||||
private void ChatOnOnChatMessage(XivChatType type, uint senderId, string sender, byte[] rawMessage,
|
private void ChatOnOnChatMessage(XivChatType type, uint senderId, ref StdString sender,
|
||||||
ref string message, ref bool isHandled) {
|
ref StdString message, 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 v{Assembly.GetAssembly(typeof(ChatHandlers)).GetName().Version} loaded.");
|
this.dalamud.Framework.Gui.Chat.Print($"XIVLauncher in-game addon v{Assembly.GetAssembly(typeof(ChatHandlers)).GetName().Version} loaded.");
|
||||||
|
|
@ -106,7 +107,7 @@ namespace Dalamud.Game {
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var matched = this.rmtRegex.IsMatch(message);
|
var matched = this.rmtRegex.IsMatch(message.Value);
|
||||||
if (matched) {
|
if (matched) {
|
||||||
// This seems to be a RMT ad - let's not show it
|
// This seems to be a RMT ad - let's not show it
|
||||||
Log.Debug("Handled RMT ad");
|
Log.Debug("Handled RMT ad");
|
||||||
|
|
@ -114,10 +115,11 @@ namespace Dalamud.Game {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var originalMessage = string.Copy(message);
|
var messageVal = message.Value;
|
||||||
|
var senderVal = sender.Value;
|
||||||
|
|
||||||
if (this.dalamud.Configuration.BadWords != null &&
|
if (this.dalamud.Configuration.BadWords != null &&
|
||||||
this.dalamud.Configuration.BadWords.Any(x => originalMessage.Contains(x))) {
|
this.dalamud.Configuration.BadWords.Any(x => messageVal.Contains(x))) {
|
||||||
// This seems to be in the user block list - let's not show it
|
// This seems to be in the user block list - let's not show it
|
||||||
Log.Debug("Blocklist triggered");
|
Log.Debug("Blocklist triggered");
|
||||||
isHandled = true;
|
isHandled = true;
|
||||||
|
|
@ -128,7 +130,7 @@ namespace Dalamud.Game {
|
||||||
{
|
{
|
||||||
foreach (var regex in retainerSaleRegexes[dalamud.StartInfo.Language])
|
foreach (var regex in retainerSaleRegexes[dalamud.StartInfo.Language])
|
||||||
{
|
{
|
||||||
var matchInfo = regex.Match(message);
|
var matchInfo = regex.Match(message.Value);
|
||||||
|
|
||||||
// we no longer really need to do/validate the item matching since we read the id from the byte array
|
// we no longer really need to do/validate the item matching since we read the id from the byte array
|
||||||
// but we'd be checking the main match anyway
|
// but we'd be checking the main match anyway
|
||||||
|
|
@ -136,7 +138,7 @@ namespace Dalamud.Game {
|
||||||
if (!itemInfo.Success)
|
if (!itemInfo.Success)
|
||||||
continue;
|
continue;
|
||||||
//var itemName = SeString.Parse(itemInfo.Value).Output;
|
//var itemName = SeString.Parse(itemInfo.Value).Output;
|
||||||
var (itemId, isHQ) = (ValueTuple<int, bool>)(SeString.Parse(rawMessage).Payloads[0].Param1);
|
var (itemId, isHQ) = (ValueTuple<int, bool>)(SeString.Parse(message.RawData).Payloads[0].Param1);
|
||||||
|
|
||||||
Log.Debug($"Probable retainer sale: {message}, decoded item {itemId}, HQ {isHQ}");
|
Log.Debug($"Probable retainer sale: {message}, decoded item {itemId}, HQ {isHQ}");
|
||||||
|
|
||||||
|
|
@ -152,27 +154,31 @@ namespace Dalamud.Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Task.Run(() => this.dalamud.BotManager.ProcessChatMessage(type, originalMessage, sender).GetAwaiter()
|
Task.Run(() => this.dalamud.BotManager.ProcessChatMessage(type, messageVal, senderVal).GetAwaiter()
|
||||||
.GetResult());
|
.GetResult());
|
||||||
|
|
||||||
|
|
||||||
if ((this.HandledChatTypeColors.ContainsKey(type) || type == XivChatType.Say || type == XivChatType.Shout ||
|
if ((this.HandledChatTypeColors.ContainsKey(type) || type == XivChatType.Say || type == XivChatType.Shout ||
|
||||||
type == XivChatType.Alliance || type == XivChatType.TellOutgoing || type == XivChatType.Yell) && !message.Contains((char)0x02)) {
|
type == XivChatType.Alliance || type == XivChatType.TellOutgoing || type == XivChatType.Yell) && !message.Value.Contains((char)0x02)) {
|
||||||
var italicsStart = message.IndexOf("*");
|
var italicsStart = message.Value.IndexOf("*");
|
||||||
var italicsEnd = message.IndexOf("*", italicsStart + 1);
|
var italicsEnd = message.Value.IndexOf("*", italicsStart + 1);
|
||||||
|
|
||||||
|
var messageString = message.Value;
|
||||||
|
|
||||||
while (italicsEnd != -1) {
|
while (italicsEnd != -1) {
|
||||||
var it = MakeItalics(
|
var it = MakeItalics(
|
||||||
message.Substring(italicsStart, italicsEnd - italicsStart + 1).Replace("*", ""));
|
messageString.Substring(italicsStart, italicsEnd - italicsStart + 1).Replace("*", ""));
|
||||||
message = message.Remove(italicsStart, italicsEnd - italicsStart + 1);
|
messageString = messageString.Remove(italicsStart, italicsEnd - italicsStart + 1);
|
||||||
message = message.Insert(italicsStart, it);
|
messageString = messageString.Insert(italicsStart, it);
|
||||||
italicsStart = message.IndexOf("*");
|
italicsStart = messageString.IndexOf("*");
|
||||||
italicsEnd = message.IndexOf("*", italicsStart + 1);
|
italicsEnd = messageString.IndexOf("*", italicsStart + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message.RawData = Encoding.UTF8.GetBytes(messageString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var linkMatch = this.urlRegex.Match(message);
|
var linkMatch = this.urlRegex.Match(message.Value);
|
||||||
if (linkMatch.Value.Length > 0)
|
if (linkMatch.Value.Length > 0)
|
||||||
LastLink = linkMatch.Value;
|
LastLink = linkMatch.Value;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Dalamud.Game.Chat;
|
using Dalamud.Game.Chat;
|
||||||
|
using Dalamud.Game.Internal.Libc;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Dalamud.Game.Command {
|
namespace Dalamud.Game.Command {
|
||||||
|
|
@ -50,10 +51,10 @@ namespace Dalamud.Game.Command {
|
||||||
dalamud.Framework.Gui.Chat.OnChatMessage += OnChatMessage;
|
dalamud.Framework.Gui.Chat.OnChatMessage += OnChatMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnChatMessage(XivChatType type, uint senderId, string sender, byte[] rawMessage,
|
private void OnChatMessage(XivChatType type, uint senderId, ref StdString sender,
|
||||||
ref string message, ref bool isHandled) {
|
ref StdString message, ref bool isHandled) {
|
||||||
if (type == XivChatType.GatheringSystemMessage && senderId == 0) {
|
if (type == XivChatType.GatheringSystemMessage && senderId == 0) {
|
||||||
var cmdMatch = this.CommandRegex.Match(message).Groups["command"];
|
var cmdMatch = this.CommandRegex.Match(message.Value).Groups["command"];
|
||||||
if (cmdMatch.Success) {
|
if (cmdMatch.Success) {
|
||||||
// Yes, it's a chat command.
|
// Yes, it's a chat command.
|
||||||
var command = cmdMatch.Value;
|
var command = cmdMatch.Value;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ 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;
|
||||||
|
using Discord.Rest;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Dalamud.Game.Internal.Gui {
|
namespace Dalamud.Game.Internal.Gui {
|
||||||
|
|
@ -14,7 +15,7 @@ namespace Dalamud.Game.Internal.Gui {
|
||||||
IntPtr message,
|
IntPtr message,
|
||||||
uint senderId, IntPtr parameter);
|
uint senderId, IntPtr parameter);
|
||||||
|
|
||||||
public delegate void OnMessageDelegate(XivChatType type, uint senderId, string sender, byte[] rawMessage, ref string message,
|
public delegate void OnMessageDelegate(XivChatType type, uint senderId, ref StdString sender, ref StdString message,
|
||||||
ref bool isHandled);
|
ref bool isHandled);
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -84,25 +85,23 @@ namespace Dalamud.Game.Internal.Gui {
|
||||||
IntPtr retVal = IntPtr.Zero;
|
IntPtr retVal = IntPtr.Zero;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ByteWrapper messageBytes = new ByteWrapper();
|
|
||||||
|
|
||||||
var senderName = StdString.ReadFromPointer(pSenderName);
|
var senderName = StdString.ReadFromPointer(pSenderName);
|
||||||
var message = StdString.ReadFromPointer(pMessage, messageBytes);
|
var message = StdString.ReadFromPointer(pMessage);
|
||||||
|
|
||||||
Log.Debug($"HandlePrintMessageDetour {manager} - [{chattype}] [{BitConverter.ToString(Encoding.UTF8.GetBytes(message)).Replace("-", " ")}] {message} from {senderName}");
|
Log.Debug($"HandlePrintMessageDetour {manager} - [{chattype}] [{BitConverter.ToString(message.RawData).Replace("-", " ")}] {message} from {senderName}");
|
||||||
// Log.Debug($"Got message bytes {BitConverter.ToString(messageBytes.Bytes).Replace("-", " ")}");
|
// Log.Debug($"Got message bytes {BitConverter.ToString(messageBytes.Bytes).Replace("-", " ")}");
|
||||||
|
|
||||||
var originalMessage = string.Copy(message);
|
var originalMessage = message.RawData.Clone();
|
||||||
|
|
||||||
// Call events
|
// Call events
|
||||||
var isHandled = false;
|
var isHandled = false;
|
||||||
OnChatMessage?.Invoke(chattype, senderid, senderName, messageBytes.Bytes, ref message, ref isHandled);
|
OnChatMessage?.Invoke(chattype, senderid, ref senderName, ref message, ref isHandled);
|
||||||
|
|
||||||
var messagePtr = pMessage;
|
var messagePtr = pMessage;
|
||||||
OwnedStdString allocatedString = null;
|
OwnedStdString allocatedString = null;
|
||||||
|
|
||||||
if (originalMessage != message) {
|
if (originalMessage != message.RawData) {
|
||||||
allocatedString = this.dalamud.Framework.Libc.NewString(Encoding.UTF8.GetBytes(message));
|
allocatedString = this.dalamud.Framework.Libc.NewString(message.RawData);
|
||||||
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;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ namespace Dalamud.Game.Internal.Libc {
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Read() {
|
public StdString Read() {
|
||||||
return StdString.ReadFromPointer(Address);
|
return StdString.ReadFromPointer(Address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Dalamud.Game.Internal.Libc {
|
namespace Dalamud.Game.Internal.Libc {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interation with std::string
|
/// Interation with std::string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class StdString {
|
public class StdString {
|
||||||
public static string ReadFromPointer(IntPtr cstring, ByteWrapper bytes = null) {
|
public static StdString ReadFromPointer(IntPtr cstring) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if (cstring == IntPtr.Zero) {
|
if (cstring == IntPtr.Zero) {
|
||||||
throw new ArgumentNullException(nameof(cstring));
|
throw new ArgumentNullException(nameof(cstring));
|
||||||
|
|
@ -18,35 +21,29 @@ namespace Dalamud.Game.Internal.Libc {
|
||||||
if (innerAddress == IntPtr.Zero) {
|
if (innerAddress == IntPtr.Zero) {
|
||||||
throw new NullReferenceException("Inner reference to the cstring is null.");
|
throw new NullReferenceException("Inner reference to the cstring is null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var pInner = (sbyte*) innerAddress.ToPointer();
|
|
||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
// Count the number of chars. String is assumed to be zero-terminated.
|
// Count the number of chars. String is assumed to be zero-terminated.
|
||||||
while (*(pInner + count) != 0) {
|
while (Marshal.ReadByte(innerAddress + count) != 0) {
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// raw copy if requested, as the string conversion returned from this function is lossy
|
// raw copy, as UTF8 string conversion is lossy
|
||||||
if (bytes != null)
|
var rawData = new byte[count];
|
||||||
{
|
Marshal.Copy(innerAddress, rawData, 0, count);
|
||||||
bytes.Bytes = new byte[count];
|
|
||||||
for (int i = 0; i < count; i++)
|
return new StdString {
|
||||||
{
|
RawData = rawData,
|
||||||
bytes.Bytes[i] = (byte)pInner[i];
|
Value = Encoding.UTF8.GetString(rawData)
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return new string(pInner, 0, count, Encoding.UTF8);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
private StdString() { }
|
||||||
/// Wrapper so that we can use an optional byte[] as a parameter
|
|
||||||
/// </summary>
|
public string Value { get; private set; }
|
||||||
public class ByteWrapper
|
|
||||||
{
|
public byte[] RawData { get; set; }
|
||||||
public byte[] Bytes { get; set; } = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue