mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-24 05:31:51 +01:00
refactor: use sigs instead of opcodes for network
This commit is contained in:
parent
671e800bb3
commit
e8231afee0
2 changed files with 219 additions and 150 deletions
|
|
@ -220,6 +220,8 @@ namespace Dalamud {
|
|||
this.SigScanner.Dispose();
|
||||
|
||||
this.Data.Dispose();
|
||||
|
||||
this.NetworkHandlers.Dispose();
|
||||
}
|
||||
|
||||
#region Interface
|
||||
|
|
|
|||
|
|
@ -4,17 +4,15 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Game.Internal.Network;
|
||||
using Dalamud.Game.Network.MarketBoardUploaders;
|
||||
using Dalamud.Game.Network.Structures;
|
||||
using Dalamud.Game.Network.Universalis.MarketBoardUploaders;
|
||||
using Lumina.Excel;
|
||||
using Dalamud.Hooking;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Network {
|
||||
public class NetworkHandlers {
|
||||
public class NetworkHandlers : IDisposable {
|
||||
private readonly Dalamud dalamud;
|
||||
|
||||
private readonly List<MarketBoardItemRequest> marketBoardRequests = new List<MarketBoardItemRequest>();
|
||||
|
|
@ -22,6 +20,21 @@ namespace Dalamud.Game.Network {
|
|||
private readonly bool optOutMbUploads;
|
||||
private readonly IMarketBoardUploader uploader;
|
||||
|
||||
private delegate IntPtr OnCfNotifyPopDelegate(IntPtr dataPtr);
|
||||
private readonly Hook<OnCfNotifyPopDelegate> onCfNotifyPop;
|
||||
|
||||
private delegate IntPtr OnMarketBoardRequestItemDelegate(IntPtr a1, IntPtr dataPtr);
|
||||
private readonly Hook<OnMarketBoardRequestItemDelegate> onMarketBoardRequestItem;
|
||||
|
||||
private delegate IntPtr OnMarketBoardOfferingsDelegate(IntPtr a1, IntPtr dataPtr);
|
||||
private readonly Hook<OnMarketBoardOfferingsDelegate> onMarketBoardOfferings;
|
||||
|
||||
private delegate IntPtr OnMarketBoardHistoryDelegate(IntPtr a1, IntPtr dataPtr);
|
||||
private readonly Hook<OnMarketBoardHistoryDelegate> onMarketBoardHistory;
|
||||
|
||||
private delegate IntPtr OnMarketBoardTaxRatesDelegate(IntPtr a1, int a2, IntPtr dataPtr);
|
||||
private readonly Hook<OnMarketBoardTaxRatesDelegate> onMarketBoardTaxRates;
|
||||
|
||||
public delegate Task CfPop(ContentFinderCondition cfc);
|
||||
public event CfPop ProcessCfPop;
|
||||
|
||||
|
|
@ -31,185 +44,239 @@ namespace Dalamud.Game.Network {
|
|||
|
||||
this.uploader = new UniversalisMarketBoardUploader(dalamud);
|
||||
|
||||
dalamud.Framework.Network.OnNetworkMessage += OnNetworkMessage;
|
||||
var onCfNotifyPopPtr = dalamud.SigScanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 60 48 8B D9 48 8D 0D ?? ?? ?? ??");
|
||||
if (onCfNotifyPopPtr == IntPtr.Zero) {
|
||||
Log.Error("Could not find OnCfNotifyPop pointer from signature");
|
||||
} else {
|
||||
this.onCfNotifyPop = new Hook<OnCfNotifyPopDelegate>(onCfNotifyPopPtr, new OnCfNotifyPopDelegate(this.OnCfNotifyPop));
|
||||
this.onCfNotifyPop.Enable();
|
||||
}
|
||||
|
||||
var onMbReqItemPtr = dalamud.SigScanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 40 48 8B 0D ?? ?? ?? ?? 48 8B DA E8 ?? ?? ?? ?? 48 8B F8");
|
||||
if (onMbReqItemPtr == IntPtr.Zero) {
|
||||
Log.Error("Could not find OnMarketBoardRequestItem pointer from signature");
|
||||
} else {
|
||||
this.onMarketBoardRequestItem = new Hook<OnMarketBoardRequestItemDelegate>(onMbReqItemPtr, new OnMarketBoardRequestItemDelegate(this.OnMarketBoardRequestItem));
|
||||
this.onMarketBoardRequestItem.Enable();
|
||||
}
|
||||
|
||||
var onMbOfferingsPtr = dalamud.SigScanner.ScanText("40 53 48 83 EC 20 48 8B 0D ?? ?? ?? ?? 48 8B DA E8 ?? ?? ?? ?? 48 85 C0 74 ?? 4C 8B 00 48 8B C8 41 FF 90 ?? ?? ?? ?? 48 8B C8 BA 09 00 00 00 E8 ?? ?? ?? ?? 48 85 C0 74 ?? 4C 8B 00");
|
||||
if (onMbOfferingsPtr == IntPtr.Zero) {
|
||||
Log.Error("Could not find OnMarketBoardOfferings pointer from signature");
|
||||
} else {
|
||||
this.onMarketBoardOfferings = new Hook<OnMarketBoardOfferingsDelegate>(onMbOfferingsPtr, new OnMarketBoardOfferingsDelegate(this.OnMarketBoardOfferings));
|
||||
this.onMarketBoardOfferings.Enable();
|
||||
}
|
||||
|
||||
// there is not a unique signature with wildcards for this function
|
||||
var onMbHistoryPtr = dalamud.SigScanner.ScanText("40 53 48 83 EC 20 48 8B 0D CB 2A B9 00");
|
||||
if (onMbHistoryPtr == IntPtr.Zero) {
|
||||
Log.Error("Could not find OnMarketBoardHistory pointer from signature");
|
||||
} else {
|
||||
this.onMarketBoardHistory = new Hook<OnMarketBoardHistoryDelegate>(onMbHistoryPtr, new OnMarketBoardHistoryDelegate(this.OnMarketBoardHistory));
|
||||
this.onMarketBoardHistory.Enable();
|
||||
}
|
||||
|
||||
var onMbTaxRatesPtr = dalamud.SigScanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 49 8B F8 48 8B D9 49 83 C0 08 E8 ?? ?? ?? ?? 0F B6 07 84 C0 74 ?? 44 0F B6 C0 48 8D 8B ?? ?? ?? ?? B2 04");
|
||||
if (onMbTaxRatesPtr == IntPtr.Zero) {
|
||||
Log.Error("Could not find OnMarketBoardTaxRates pointer from signature");
|
||||
} else {
|
||||
this.onMarketBoardTaxRates = new Hook<OnMarketBoardTaxRatesDelegate>(onMbTaxRatesPtr, new OnMarketBoardTaxRatesDelegate(this.OnMarketBoardTaxRates));
|
||||
this.onMarketBoardTaxRates.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNetworkMessage(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction) {
|
||||
if (direction != NetworkMessageDirection.ZoneDown)
|
||||
return;
|
||||
|
||||
private IntPtr OnCfNotifyPop(IntPtr dataPtr) {
|
||||
if (!this.dalamud.Data.IsDataReady)
|
||||
return;
|
||||
goto Return;
|
||||
|
||||
if (opCode == this.dalamud.Data.ServerOpCodes["CfNotifyPop"]) {
|
||||
var data = new byte[64];
|
||||
Marshal.Copy(dataPtr, data, 0, 64);
|
||||
var data = new byte[64];
|
||||
Marshal.Copy(dataPtr, data, 0, 64);
|
||||
|
||||
var notifyType = data[0];
|
||||
var contentFinderConditionId = BitConverter.ToUInt16(data, 0x14);
|
||||
var notifyType = data[0];
|
||||
var contentFinderConditionId = BitConverter.ToUInt16(data, 0x14);
|
||||
|
||||
if (notifyType != 3)
|
||||
return;
|
||||
if (notifyType != 3)
|
||||
goto Return;
|
||||
|
||||
var contentFinderCondition = this.dalamud.Data.GetExcelSheet<ContentFinderCondition>().GetRow(contentFinderConditionId);
|
||||
var contentFinderCondition = this.dalamud.Data.GetExcelSheet<ContentFinderCondition>().GetRow(contentFinderConditionId);
|
||||
|
||||
if (contentFinderCondition == null)
|
||||
{
|
||||
Log.Error("CFC key {0} not in lumina data.", contentFinderConditionId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(contentFinderCondition.Name)) {
|
||||
contentFinderCondition.Name = "Duty Roulette";
|
||||
contentFinderCondition.Image = 112324;
|
||||
}
|
||||
|
||||
if (this.dalamud.Configuration.DutyFinderTaskbarFlash && !NativeFunctions.ApplicationIsActivated()) {
|
||||
var flashInfo = new NativeFunctions.FLASHWINFO
|
||||
{
|
||||
cbSize = (uint)Marshal.SizeOf<NativeFunctions.FLASHWINFO>(),
|
||||
uCount = uint.MaxValue,
|
||||
dwTimeout = 0,
|
||||
dwFlags = NativeFunctions.FlashWindow.FLASHW_ALL |
|
||||
NativeFunctions.FlashWindow.FLASHW_TIMERNOFG,
|
||||
hwnd = Process.GetCurrentProcess().MainWindowHandle
|
||||
};
|
||||
NativeFunctions.FlashWindowEx(ref flashInfo);
|
||||
}
|
||||
|
||||
Task.Run(async () => {
|
||||
if(this.dalamud.Configuration.DutyFinderChatMessage)
|
||||
this.dalamud.Framework.Gui.Chat.Print("Duty pop: " + contentFinderCondition.Name);
|
||||
|
||||
await this.ProcessCfPop?.Invoke(contentFinderCondition);
|
||||
});
|
||||
|
||||
return;
|
||||
if (contentFinderCondition == null) {
|
||||
Log.Error("CFC key {0} not in lumina data.", contentFinderConditionId);
|
||||
goto Return;
|
||||
}
|
||||
|
||||
if (!this.optOutMbUploads) {
|
||||
if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardItemRequestStart"]) {
|
||||
var catalogId = (uint) Marshal.ReadInt32(dataPtr);
|
||||
var amount = Marshal.ReadByte(dataPtr + 0xB);
|
||||
if (string.IsNullOrEmpty(contentFinderCondition.Name)) {
|
||||
contentFinderCondition.Name = "Duty Roulette";
|
||||
contentFinderCondition.Image = 112324;
|
||||
}
|
||||
|
||||
this.marketBoardRequests.Add(new MarketBoardItemRequest {
|
||||
CatalogId = catalogId,
|
||||
AmountToArrive = amount,
|
||||
Listings = new List<MarketBoardCurrentOfferings.MarketBoardItemListing>(),
|
||||
History = new List<MarketBoardHistory.MarketBoardHistoryListing>()
|
||||
});
|
||||
if (this.dalamud.Configuration.DutyFinderTaskbarFlash && !NativeFunctions.ApplicationIsActivated()) {
|
||||
var flashInfo = new NativeFunctions.FLASHWINFO {
|
||||
cbSize = (uint)Marshal.SizeOf<NativeFunctions.FLASHWINFO>(),
|
||||
uCount = uint.MaxValue,
|
||||
dwTimeout = 0,
|
||||
dwFlags = NativeFunctions.FlashWindow.FLASHW_ALL |
|
||||
NativeFunctions.FlashWindow.FLASHW_TIMERNOFG,
|
||||
hwnd = Process.GetCurrentProcess().MainWindowHandle
|
||||
};
|
||||
NativeFunctions.FlashWindowEx(ref flashInfo);
|
||||
}
|
||||
|
||||
Log.Verbose($"NEW MB REQUEST START: item#{catalogId} amount#{amount}");
|
||||
return;
|
||||
}
|
||||
Task.Run(async () => {
|
||||
if (this.dalamud.Configuration.DutyFinderChatMessage)
|
||||
this.dalamud.Framework.Gui.Chat.Print("Duty pop: " + contentFinderCondition.Name);
|
||||
|
||||
if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardOfferings"]) {
|
||||
var listing = MarketBoardCurrentOfferings.Read(dataPtr);
|
||||
await this.ProcessCfPop?.Invoke(contentFinderCondition);
|
||||
});
|
||||
|
||||
var request =
|
||||
this.marketBoardRequests.LastOrDefault(
|
||||
r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone);
|
||||
Return:
|
||||
return this.onCfNotifyPop.Original(dataPtr);
|
||||
}
|
||||
|
||||
if (request == null) {
|
||||
Log.Error(
|
||||
$"Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}");
|
||||
return;
|
||||
}
|
||||
private IntPtr OnMarketBoardRequestItem(IntPtr a1, IntPtr dataPtr) {
|
||||
if (!this.dalamud.Data.IsDataReady || this.optOutMbUploads)
|
||||
goto Return;
|
||||
|
||||
if (request.Listings.Count + listing.ItemListings.Count > request.AmountToArrive) {
|
||||
Log.Error(
|
||||
$"Too many Market Board listings received for request: {request.Listings.Count + listing.ItemListings.Count} > {request.AmountToArrive} item#{listing.ItemListings[0].CatalogId}");
|
||||
return;
|
||||
}
|
||||
var catalogId = (uint)Marshal.ReadInt32(dataPtr);
|
||||
var amount = Marshal.ReadByte(dataPtr + 0xB);
|
||||
|
||||
if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId) {
|
||||
Log.Error(
|
||||
$"Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}");
|
||||
return;
|
||||
}
|
||||
this.marketBoardRequests.Add(new MarketBoardItemRequest {
|
||||
CatalogId = catalogId,
|
||||
AmountToArrive = amount,
|
||||
Listings = new List<MarketBoardCurrentOfferings.MarketBoardItemListing>(),
|
||||
History = new List<MarketBoardHistory.MarketBoardHistoryListing>()
|
||||
});
|
||||
|
||||
if (request.ListingsRequestId == -1 && request.Listings.Count > 0) {
|
||||
Log.Error(
|
||||
$"Market Board data request sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
|
||||
return;
|
||||
}
|
||||
Log.Verbose($"NEW MB REQUEST START: item#{catalogId} amount#{amount}");
|
||||
|
||||
if (request.ListingsRequestId == -1) {
|
||||
request.ListingsRequestId = listing.RequestId;
|
||||
Log.Verbose($"First Market Board packet in sequence: {listing.RequestId}");
|
||||
}
|
||||
Return:
|
||||
return this.onMarketBoardRequestItem.Original(a1, dataPtr);
|
||||
}
|
||||
|
||||
request.Listings.AddRange(listing.ItemListings);
|
||||
private IntPtr OnMarketBoardOfferings(IntPtr a1, IntPtr dataPtr) {
|
||||
if (!this.dalamud.Data.IsDataReady || this.optOutMbUploads)
|
||||
goto Return;
|
||||
|
||||
Log.Verbose("Added {0} ItemListings to request#{1}, now {2}/{3}, item#{4}",
|
||||
listing.ItemListings.Count, request.ListingsRequestId, request.Listings.Count,
|
||||
request.AmountToArrive, request.CatalogId);
|
||||
var listing = MarketBoardCurrentOfferings.Read(dataPtr);
|
||||
|
||||
if (request.IsDone) {
|
||||
Log.Verbose("Market Board request finished, starting upload: request#{0} item#{1} amount#{2}",
|
||||
request.ListingsRequestId, request.CatalogId, request.AmountToArrive);
|
||||
try {
|
||||
Task.Run(() => this.uploader.Upload(request));
|
||||
} catch (Exception ex) {
|
||||
Log.Error(ex, "Market Board data upload failed.");
|
||||
}
|
||||
}
|
||||
var request =
|
||||
this.marketBoardRequests.LastOrDefault(
|
||||
r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone);
|
||||
|
||||
return;
|
||||
}
|
||||
if (request == null) {
|
||||
Log.Error(
|
||||
$"Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}");
|
||||
goto Return;
|
||||
}
|
||||
|
||||
if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardHistory"]) {
|
||||
var listing = MarketBoardHistory.Read(dataPtr);
|
||||
if (request.Listings.Count + listing.ItemListings.Count > request.AmountToArrive) {
|
||||
Log.Error(
|
||||
$"Too many Market Board listings received for request: {request.Listings.Count + listing.ItemListings.Count} > {request.AmountToArrive} item#{listing.ItemListings[0].CatalogId}");
|
||||
goto Return;
|
||||
}
|
||||
|
||||
var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId);
|
||||
if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId) {
|
||||
Log.Error(
|
||||
$"Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}");
|
||||
goto Return;
|
||||
}
|
||||
|
||||
if (request == null) {
|
||||
Log.Error(
|
||||
$"Market Board data arrived without a corresponding request: item#{listing.CatalogId}");
|
||||
return;
|
||||
}
|
||||
if (request.ListingsRequestId == -1 && request.Listings.Count > 0) {
|
||||
Log.Error(
|
||||
$"Market Board data request sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
|
||||
goto Return;
|
||||
}
|
||||
|
||||
if (request.ListingsRequestId != -1) {
|
||||
Log.Error(
|
||||
$"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
|
||||
return;
|
||||
}
|
||||
if (request.ListingsRequestId == -1) {
|
||||
request.ListingsRequestId = listing.RequestId;
|
||||
Log.Verbose($"First Market Board packet in sequence: {listing.RequestId}");
|
||||
}
|
||||
|
||||
request.History.AddRange(listing.HistoryListings);
|
||||
request.Listings.AddRange(listing.ItemListings);
|
||||
|
||||
Log.Verbose("Added history for item#{0}", listing.CatalogId);
|
||||
Log.Verbose("Added {0} ItemListings to request#{1}, now {2}/{3}, item#{4}",
|
||||
listing.ItemListings.Count, request.ListingsRequestId, request.Listings.Count,
|
||||
request.AmountToArrive, request.CatalogId);
|
||||
|
||||
if (request.AmountToArrive == 0) {
|
||||
Log.Verbose("Request had 0 amount, uploading now");
|
||||
|
||||
try
|
||||
{
|
||||
Task.Run(() => this.uploader.Upload(request));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Market Board data upload failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opCode == this.dalamud.Data.ServerOpCodes["MarketTaxRates"])
|
||||
{
|
||||
var taxes = MarketTaxRates.Read(dataPtr);
|
||||
|
||||
Log.Verbose("MarketTaxRates: limsa#{0} grid#{1} uldah#{2} ish#{3} kugane#{4} cr#{5}",
|
||||
taxes.LimsaLominsaTax, taxes.GridaniaTax, taxes.UldahTax, taxes.IshgardTax, taxes.KuganeTax, taxes.CrystariumTax);
|
||||
try
|
||||
{
|
||||
Task.Run(() => this.uploader.UploadTax(taxes));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Market Board data upload failed.");
|
||||
}
|
||||
if (request.IsDone) {
|
||||
Log.Verbose("Market Board request finished, starting upload: request#{0} item#{1} amount#{2}",
|
||||
request.ListingsRequestId, request.CatalogId, request.AmountToArrive);
|
||||
try {
|
||||
Task.Run(() => this.uploader.Upload(request));
|
||||
} catch (Exception ex) {
|
||||
Log.Error(ex, "Market Board data upload failed.");
|
||||
}
|
||||
}
|
||||
|
||||
Return:
|
||||
return this.onMarketBoardOfferings.Original(a1, dataPtr);
|
||||
}
|
||||
|
||||
private IntPtr OnMarketBoardHistory(IntPtr a1, IntPtr dataPtr) {
|
||||
Log.Verbose("history time");
|
||||
|
||||
if (!this.dalamud.Data.IsDataReady || this.optOutMbUploads)
|
||||
goto Return;
|
||||
|
||||
var listing = MarketBoardHistory.Read(dataPtr);
|
||||
|
||||
var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId);
|
||||
|
||||
if (request == null) {
|
||||
Log.Error(
|
||||
$"Market Board data arrived without a corresponding request: item#{listing.CatalogId}");
|
||||
goto Return;
|
||||
}
|
||||
|
||||
if (request.ListingsRequestId != -1) {
|
||||
Log.Error(
|
||||
$"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
|
||||
goto Return;
|
||||
}
|
||||
|
||||
request.History.AddRange(listing.HistoryListings);
|
||||
|
||||
Log.Verbose("Added history for item#{0}", listing.CatalogId);
|
||||
|
||||
if (request.AmountToArrive == 0) {
|
||||
Log.Verbose("Request had 0 amount, uploading now");
|
||||
|
||||
try {
|
||||
Task.Run(() => this.uploader.Upload(request));
|
||||
} catch (Exception ex) {
|
||||
Log.Error(ex, "Market Board data upload failed.");
|
||||
}
|
||||
}
|
||||
|
||||
Return:
|
||||
return this.onMarketBoardHistory.Original(a1, dataPtr);
|
||||
}
|
||||
|
||||
private IntPtr OnMarketBoardTaxRates(IntPtr a1, int a2, IntPtr dataPtr) {
|
||||
if (!this.dalamud.Data.IsDataReady || this.optOutMbUploads)
|
||||
goto Return;
|
||||
|
||||
var taxes = MarketTaxRates.Read(dataPtr);
|
||||
|
||||
Log.Verbose("MarketTaxRates: limsa#{0} grid#{1} uldah#{2} ish#{3} kugane#{4} cr#{5}",
|
||||
taxes.LimsaLominsaTax, taxes.GridaniaTax, taxes.UldahTax, taxes.IshgardTax, taxes.KuganeTax, taxes.CrystariumTax);
|
||||
try {
|
||||
Task.Run(() => this.uploader.UploadTax(taxes));
|
||||
} catch (Exception ex) {
|
||||
Log.Error(ex, "Market Board data upload failed.");
|
||||
}
|
||||
|
||||
Return:
|
||||
return this.onMarketBoardTaxRates.Original(a1, a2, dataPtr);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.onCfNotifyPop?.Dispose();
|
||||
this.onMarketBoardRequestItem?.Dispose();
|
||||
this.onMarketBoardOfferings?.Dispose();
|
||||
this.onMarketBoardHistory?.Dispose();
|
||||
this.onMarketBoardTaxRates?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue