changes for retainer sale notification parsing; expose message byte array to handlers, implement regex matching for retainer sale notifications and forward the parsed data to discord

This commit is contained in:
meli 2019-11-21 15:35:05 -08:00
parent 4b07b9fee6
commit 6317558db6
4 changed files with 89 additions and 11 deletions

View file

@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
@ -54,6 +54,34 @@ namespace Dalamud.Game {
new Regex(@"(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?",
RegexOptions.Compiled);
private readonly Dictionary<ClientLanguage, Regex[]> retainerSaleRegexes = new Dictionary<ClientLanguage, Regex[]>() {
{
ClientLanguage.Japanese, new Regex[] {
new Regex(@"^(?:.+)マーケットに(?<origValue>[\d,.]+)ギルで出品した(?<item>.*)×(?<count>[\d,.]+)が売れ、(?<value>[\d,.]+)ギルを入手しました。$", RegexOptions.Compiled),
new Regex(@"^(?:.+)マーケットに(?<origValue>[\d,.]+)ギルで出品した(?<item>.*)が売れ、(?<value>[\d,.]+)ギルを入手しました。$", RegexOptions.Compiled)
}
},
{
ClientLanguage.English, new Regex[]
{
new Regex(@"^(?<item>.+) you put up for sale in the (?:.+) markets (?:have|has) sold for (?<value>[\d,.]+) gil \(after fees\)\.$", RegexOptions.Compiled)
}
},
{
ClientLanguage.German, new Regex[]
{
new Regex(@"^Dein Gehilfe hat (?<item>.+) auf dem Markt von (?:.+) für (?<value>[\d,.]+) Gil verkauft\.$", RegexOptions.Compiled),
new Regex(@"^Dein Gehilfe hat (?<item>.+) auf dem Markt von (?:.+) verkauft und (?<value>[\d,.]+) Gil erhalten\.$", RegexOptions.Compiled)
}
},
{
ClientLanguage.French, new Regex[]
{
new Regex(@"^Un servant a vendu (?<item>.+) pour (?<value>[\d,.]+) gil à (?:.+)\.$", RegexOptions.Compiled)
}
}
};
private bool hasSeenLoadingMsg;
public ChatHandlers(Dalamud dalamud) {
@ -65,8 +93,8 @@ namespace Dalamud.Game {
public string LastLink { get; private set; }
private void ChatOnOnChatMessage(XivChatType type, uint senderId, string sender, ref string message,
ref bool isHandled) {
private void ChatOnOnChatMessage(XivChatType type, uint senderId, string sender, byte[] rawMessage,
ref string message, ref bool isHandled) {
if (type == XivChatType.Notice && !this.hasSeenLoadingMsg) {
this.dalamud.Framework.Gui.Chat.Print($"XIVLauncher in-game addon v{Assembly.GetAssembly(typeof(ChatHandlers)).GetName().Version} loaded.");
@ -96,8 +124,36 @@ namespace Dalamud.Game {
return;
}
if (type == XivChatType.RetainerSale)
{
foreach (var regex in retainerSaleRegexes[dalamud.StartInfo.Language])
{
var matchInfo = regex.Match(message);
// 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
var itemInfo = matchInfo.Groups["item"];
if (!itemInfo.Success)
continue;
//var itemName = SeString.Parse(itemInfo.Value).Output;
var (itemId, isHQ) = (ValueTuple<int, bool>)(SeString.Parse(rawMessage).Payloads[0].Param1);
Log.Debug($"Probable retainer sale: {message}, decoded item {itemId}, HQ {isHQ}");
int itemValue = 0;
var valueInfo = matchInfo.Groups["value"];
// not sure if using a culture here would work correctly, so just strip symbols instead
if (!valueInfo.Success || !int.TryParse(valueInfo.Value.Replace(",", "").Replace(".", ""), out itemValue))
continue;
Task.Run(() => this.dalamud.BotManager.ProcessRetainerSale(itemId, itemValue, isHQ));
break;
}
}
Task.Run(() => this.dalamud.BotManager.ProcessChatMessage(type, originalMessage, sender).GetAwaiter()
.GetResult());
.GetResult());
if ((this.HandledChatTypeColors.ContainsKey(type) || type == XivChatType.Say || type == XivChatType.Shout ||

View file

@ -50,8 +50,8 @@ namespace Dalamud.Game.Command {
dalamud.Framework.Gui.Chat.OnChatMessage += OnChatMessage;
}
private void OnChatMessage(XivChatType type, uint senderId, string sender, ref string message,
ref bool isHandled) {
private void OnChatMessage(XivChatType type, uint senderId, string sender, byte[] rawMessage,
ref string message, ref bool isHandled) {
if (type == XivChatType.GatheringSystemMessage && senderId == 0) {
var cmdMatch = this.CommandRegex.Match(message).Groups["command"];
if (cmdMatch.Success) {

View file

@ -14,7 +14,7 @@ namespace Dalamud.Game.Internal.Gui {
IntPtr message,
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, byte[] rawMessage, ref string message,
ref bool isHandled);
@ -84,16 +84,19 @@ namespace Dalamud.Game.Internal.Gui {
IntPtr retVal = IntPtr.Zero;
try {
ByteWrapper messageBytes = new ByteWrapper();
var senderName = StdString.ReadFromPointer(pSenderName);
var message = StdString.ReadFromPointer(pMessage);
var message = StdString.ReadFromPointer(pMessage, messageBytes);
Log.Debug($"HandlePrintMessageDetour {manager} - [{chattype}] [{BitConverter.ToString(Encoding.UTF8.GetBytes(message)).Replace("-", " ")}] {message} from {senderName}");
// Log.Debug($"Got message bytes {BitConverter.ToString(messageBytes.Bytes).Replace("-", " ")}");
var originalMessage = string.Copy(message);
// Call events
var isHandled = false;
OnChatMessage?.Invoke(chattype, senderid, senderName, ref message, ref isHandled);
OnChatMessage?.Invoke(chattype, senderid, senderName, messageBytes.Bytes, ref message, ref isHandled);
var messagePtr = pMessage;
OwnedStdString allocatedString = null;

View file

@ -1,13 +1,14 @@
using System;
using System;
using System.Runtime.InteropServices;
using System.Text;
using Serilog;
namespace Dalamud.Game.Internal.Libc {
/// <summary>
/// Interation with std::string
/// </summary>
public static class StdString {
public static string ReadFromPointer(IntPtr cstring) {
public static string ReadFromPointer(IntPtr cstring, ByteWrapper bytes = null) {
unsafe {
if (cstring == IntPtr.Zero) {
throw new ArgumentNullException(nameof(cstring));
@ -25,9 +26,27 @@ namespace Dalamud.Game.Internal.Libc {
while (*(pInner + count) != 0) {
count += 1;
}
// raw copy if requested, as the string conversion returned from this function is lossy
if (bytes != null)
{
bytes.Bytes = new byte[count];
for (int i = 0; i < count; i++)
{
bytes.Bytes[i] = (byte)pInner[i];
}
}
return new string(pInner, 0, count, Encoding.UTF8);
}
}
}
/// <summary>
/// Wrapper so that we can use an optional byte[] as a parameter
/// </summary>
public class ByteWrapper
{
public byte[] Bytes { get; set; } = null;
}
}