diff --git a/Dalamud/Game/Network/NetworkHandlers.cs b/Dalamud/Game/Network/NetworkHandlers.cs index 790ed57d5..c918d8b83 100644 --- a/Dalamud/Game/Network/NetworkHandlers.cs +++ b/Dalamud/Game/Network/NetworkHandlers.cs @@ -15,7 +15,7 @@ using Serilog; namespace Dalamud.Game.Network { /// - /// This class handles network notifications and uploading Marketboard data. + /// This class handles network notifications and uploading market board data. /// public class NetworkHandlers { @@ -23,6 +23,8 @@ namespace Dalamud.Game.Network private readonly List marketBoardRequests = new(); + private MarketBoardPurchaseHandler marketBoardPurchaseHandler; + private readonly bool optOutMbUploads; private readonly IMarketBoardUploader uploader; @@ -30,7 +32,7 @@ namespace Dalamud.Game.Network /// Initializes a new instance of the class. /// /// The Dalamud instance. - /// Whether the client should opt out of marketboard uploads. + /// Whether the client should opt out of market board uploads. public NetworkHandlers(Dalamud dalamud, bool optOutMbUploads) { this.dalamud = dalamud; @@ -48,12 +50,22 @@ namespace Dalamud.Game.Network private void OnNetworkMessage(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction) { - if (direction != NetworkMessageDirection.ZoneDown) - return; - if (!this.dalamud.Data.IsDataReady) return; + if (direction == NetworkMessageDirection.ZoneUp) + { + if (!this.optOutMbUploads) + { + if (opCode == this.dalamud.Data.ClientOpCodes["MarketBoardPurchaseHandler"]) + { + this.marketBoardPurchaseHandler = MarketBoardPurchaseHandler.Read(dataPtr); + } + } + + return; + } + if (opCode == this.dalamud.Data.ServerOpCodes["CfNotifyPop"]) { var data = new byte[64]; @@ -256,6 +268,24 @@ namespace Dalamud.Game.Network Log.Error(ex, "Market Board data upload failed."); } } + + if (opCode == this.dalamud.Data.ServerOpCodes["MarketBoardPurchase"]) + { + if (this.marketBoardPurchaseHandler == null) + return; + + var purchase = MarketBoardPurchase.Read(dataPtr); + + // Transaction succeeded + if (purchase.ItemQuantity == this.marketBoardPurchaseHandler.ItemQuantity + && (purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId + || purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId + 1000000)) + { // HQ + Log.Information("Bought " + purchase.ItemQuantity + "x " + this.marketBoardPurchaseHandler.CatalogId + " for " + (this.marketBoardPurchaseHandler.PricePerUnit * purchase.ItemQuantity) + " gils, listing id is " + this.marketBoardPurchaseHandler.ListingId); + } + + this.marketBoardPurchaseHandler = null; + } } } } diff --git a/Dalamud/Game/Network/Structures/MarketBoardPurchase.cs b/Dalamud/Game/Network/Structures/MarketBoardPurchase.cs new file mode 100644 index 000000000..ed8051154 --- /dev/null +++ b/Dalamud/Game/Network/Structures/MarketBoardPurchase.cs @@ -0,0 +1,40 @@ +using System; +using System.IO; + +namespace Dalamud.Game.Network.Structures +{ + /// + /// Represents market board purchase information. This message is received from the + /// server when a purchase is made at a market board. + /// + internal class MarketBoardPurchase + { + /// + /// Gets the item ID of the item that was purchased. + /// + public uint CatalogId { get; private set; } + + /// + /// Gets the quantity of the item that was purchased. + /// + public uint ItemQuantity { get; private set; } + + /// + /// Reads market board purchase information from the struct at the provided pointer. + /// + /// A pointer to a struct containing market board purchase information from the server. + /// An object representing the data read. + public static unsafe MarketBoardPurchase Read(IntPtr dataPtr) + { + var output = new MarketBoardPurchase(); + + using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544); + using var reader = new BinaryReader(stream); + output.CatalogId = reader.ReadUInt32(); + stream.Position += 4; + output.ItemQuantity = reader.ReadUInt32(); + + return output; + } + } +} diff --git a/Dalamud/Game/Network/Structures/MarketBoardPurchaseHandler.cs b/Dalamud/Game/Network/Structures/MarketBoardPurchaseHandler.cs new file mode 100644 index 000000000..98d7007b0 --- /dev/null +++ b/Dalamud/Game/Network/Structures/MarketBoardPurchaseHandler.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; + +namespace Dalamud.Game.Network.Structures +{ + /// + /// Represents market board purchase information. This message is sent from the + /// client when a purchase is made at a market board. + /// + internal class MarketBoardPurchaseHandler + { + /// + /// Gets the object ID of the retainer associated with the sale. + /// + public ulong RetainerId { get; private set; } + + /// + /// Gets the object ID of the item listing. + /// + public ulong ListingId { get; private set; } + + /// + /// Gets the item ID of the item that was purchased. + /// + public uint CatalogId { get; private set; } + + /// + /// Gets the quantity of the item that was purchased. + /// + public uint ItemQuantity { get; private set; } + + /// + /// Gets the unit price of the item. + /// + public uint PricePerUnit { get; private set; } + + /// + /// Reads market board purchase information from the struct at the provided pointer. + /// + /// A pointer to a struct containing market board purchase information from the client. + /// An object representing the data read. + public static unsafe MarketBoardPurchaseHandler Read(IntPtr dataPtr) + { + var output = new MarketBoardPurchaseHandler(); + + using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544); + using var reader = new BinaryReader(stream); + output.RetainerId = reader.ReadUInt64(); + output.ListingId = reader.ReadUInt64(); + output.CatalogId = reader.ReadUInt32(); + output.ItemQuantity = reader.ReadUInt32(); + output.PricePerUnit = reader.ReadUInt32(); + + return output; + } + } +}