Refactor chat handling

This commit is contained in:
goat 2019-11-22 21:12:51 +09:00
parent 397816ef7b
commit c1aeaceb47
5 changed files with 57 additions and 54 deletions

View file

@ -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;
} }

View file

@ -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;

View file

@ -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;

View file

@ -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);
} }
} }

View file

@ -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;
} }
} }