Merge pull request #453 from daemitus/GameNetwork

This commit is contained in:
goaaats 2021-08-09 16:55:29 +02:00 committed by GitHub
commit daf115b377
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 375 additions and 117 deletions

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Game.Network;
using Dalamud.Hooking; using Dalamud.Hooking;
using Serilog; using Serilog;

View file

@ -1,6 +1,6 @@
using Dalamud.Game.Network.Structures; using Dalamud.Game.Network.Structures;
namespace Dalamud.Game.Network.MarketBoardUploaders namespace Dalamud.Game.Network.Internal.MarketBoardUploaders
{ {
/// <summary> /// <summary>
/// An interface binding for the Universalis uploader. /// An interface binding for the Universalis uploader.

View file

@ -0,0 +1,42 @@
using System.Collections.Generic;
using Dalamud.Game.Network.Structures;
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders
{
/// <summary>
/// This represents a submission to a marketboard aggregation website.
/// </summary>
internal class MarketBoardItemRequest
{
/// <summary>
/// Gets or sets the catalog ID.
/// </summary>
public uint CatalogId { get; set; }
/// <summary>
/// Gets or sets the amount to arrive.
/// </summary>
public byte AmountToArrive { get; set; }
/// <summary>
/// Gets or sets the offered item listings.
/// </summary>
public List<MarketBoardCurrentOfferings.MarketBoardItemListing> Listings { get; set; }
/// <summary>
/// Gets or sets the historical item listings.
/// </summary>
public List<MarketBoardHistory.MarketBoardHistoryListing> History { get; set; }
/// <summary>
/// Gets or sets the listing request ID.
/// </summary>
public int ListingsRequestId { get; set; } = -1;
/// <summary>
/// Gets a value indicating whether the upload is complete.
/// </summary>
public bool IsDone => this.Listings.Count == this.AmountToArrive && this.History.Count != 0;
}
}

View file

@ -1,6 +1,6 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
{ {
/// <summary> /// <summary>
/// A Universalis API structure. /// A Universalis API structure.

View file

@ -2,7 +2,7 @@ using System.Collections.Generic;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
{ {
/// <summary> /// <summary>
/// A Universalis API structure. /// A Universalis API structure.

View file

@ -1,11 +1,11 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
{ {
/// <summary> /// <summary>
/// Request payload for market board purchases. /// Request payload for market board purchases.
/// </summary> /// </summary>
public class UniversalisItemListingDeleteRequest internal class UniversalisItemListingDeleteRequest
{ {
/// <summary> /// <summary>
/// Gets or sets the object ID of the retainer associated with the sale. /// Gets or sets the object ID of the retainer associated with the sale.

View file

@ -2,7 +2,7 @@ using System.Collections.Generic;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
{ {
/// <summary> /// <summary>
/// A Universalis API structure. /// A Universalis API structure.

View file

@ -2,7 +2,7 @@ using System.Collections.Generic;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
{ {
/// <summary> /// <summary>
/// A Universalis API structure. /// A Universalis API structure.

View file

@ -1,6 +1,6 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
{ {
/// <summary> /// <summary>
/// A Universalis API structure. /// A Universalis API structure.

View file

@ -1,6 +1,6 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
{ {
/// <summary> /// <summary>
/// A Universalis API structure. /// A Universalis API structure.

View file

@ -1,6 +1,6 @@
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Dalamud.Game.Network.MarketBoardUploaders.Universalis namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
{ {
/// <summary> /// <summary>
/// A Universalis API structure. /// A Universalis API structure.

View file

@ -1,14 +1,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Dalamud.Game.Network.MarketBoardUploaders; using Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types;
using Dalamud.Game.Network.MarketBoardUploaders.Universalis;
using Dalamud.Game.Network.Structures; using Dalamud.Game.Network.Structures;
using Newtonsoft.Json; using Newtonsoft.Json;
using Serilog; using Serilog;
namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis
{ {
/// <summary> /// <summary>
/// This class represents an uploader for contributing data to Universalis. /// This class represents an uploader for contributing data to Universalis.
@ -16,8 +17,8 @@ namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders
internal class UniversalisMarketBoardUploader : IMarketBoardUploader internal class UniversalisMarketBoardUploader : IMarketBoardUploader
{ {
private const string ApiBase = "https://universalis.app"; private const string ApiBase = "https://universalis.app";
// private const string ApiBase = "https://127.0.0.1:443"; // private const string ApiBase = "https://127.0.0.1:443";
private const string ApiKey = "GGD6RdSfGyRiHM5WDnAo0Nj9Nv7aC5NDhMj3BebT"; private const string ApiKey = "GGD6RdSfGyRiHM5WDnAo0Nj9Nv7aC5NDhMj3BebT";
private readonly Dalamud dalamud; private readonly Dalamud dalamud;
@ -34,14 +35,14 @@ namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders
/// <inheritdoc/> /// <inheritdoc/>
public void Upload(MarketBoardItemRequest request) public void Upload(MarketBoardItemRequest request)
{ {
using var client = new WebClient(); using var client = new HttpClient();
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
Log.Verbose("Starting Universalis upload."); Log.Verbose("Starting Universalis upload.");
var uploader = this.dalamud.ClientState.LocalContentId; var uploader = this.dalamud.ClientState.LocalContentId;
var listingsRequestObject = new UniversalisItemListingsUploadRequest // ====================================================================================
var listingsUploadObject = new UniversalisItemListingsUploadRequest
{ {
WorldId = this.dalamud.ClientState.LocalPlayer?.CurrentWorld.Id ?? 0, WorldId = this.dalamud.ClientState.LocalPlayer?.CurrentWorld.Id ?? 0,
UploaderId = uploader.ToString(), UploaderId = uploader.ToString(),
@ -76,14 +77,17 @@ namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders
}); });
} }
listingsRequestObject.Listings.Add(universalisListing); listingsUploadObject.Listings.Add(universalisListing);
} }
var upload = JsonConvert.SerializeObject(listingsRequestObject); var listingPath = "/upload";
Log.Verbose(upload); var listingUpload = JsonConvert.SerializeObject(listingsUploadObject);
client.UploadString(ApiBase + $"/upload/{ApiKey}", "POST", upload); Log.Verbose($"{listingPath}: {listingUpload}");
client.PostAsync($"{ApiBase}{listingPath}/{ApiKey}", new StringContent(listingUpload, Encoding.UTF8, "application/json")).GetAwaiter().GetResult();
var historyRequestObject = new UniversalisHistoryUploadRequest // ====================================================================================
var historyUploadObject = new UniversalisHistoryUploadRequest
{ {
WorldId = this.dalamud.ClientState.LocalPlayer?.CurrentWorld.Id ?? 0, WorldId = this.dalamud.ClientState.LocalPlayer?.CurrentWorld.Id ?? 0,
UploaderId = uploader.ToString(), UploaderId = uploader.ToString(),
@ -93,7 +97,7 @@ namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders
foreach (var marketBoardHistoryListing in request.History) foreach (var marketBoardHistoryListing in request.History)
{ {
historyRequestObject.Entries.Add(new UniversalisHistoryEntry historyUploadObject.Entries.Add(new UniversalisHistoryEntry
{ {
BuyerName = marketBoardHistoryListing.BuyerName, BuyerName = marketBoardHistoryListing.BuyerName,
Hq = marketBoardHistoryListing.IsHq, Hq = marketBoardHistoryListing.IsHq,
@ -104,11 +108,12 @@ namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders
}); });
} }
client.Headers.Add(HttpRequestHeader.ContentType, "application/json"); var historyPath = "/upload";
var historyUpload = JsonConvert.SerializeObject(historyUploadObject);
Log.Verbose($"{historyPath}: {historyUpload}");
client.PostAsync($"{ApiBase}{historyPath}/{ApiKey}", new StringContent(historyUpload, Encoding.UTF8, "application/json")).GetAwaiter().GetResult();
var historyUpload = JsonConvert.SerializeObject(historyRequestObject); // ====================================================================================
Log.Verbose(historyUpload);
client.UploadString(ApiBase + $"/upload/{ApiKey}", "POST", historyUpload);
Log.Verbose("Universalis data upload for item#{0} completed.", request.CatalogId); Log.Verbose("Universalis data upload for item#{0} completed.", request.CatalogId);
} }
@ -116,9 +121,11 @@ namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders
/// <inheritdoc/> /// <inheritdoc/>
public void UploadTax(MarketTaxRates taxRates) public void UploadTax(MarketTaxRates taxRates)
{ {
using var client = new WebClient(); using var client = new HttpClient();
var taxRatesRequest = new UniversalisTaxUploadRequest // ====================================================================================
var taxUploadObject = new UniversalisTaxUploadRequest
{ {
WorldId = this.dalamud.ClientState.LocalPlayer?.CurrentWorld.Id ?? 0, WorldId = this.dalamud.ClientState.LocalPlayer?.CurrentWorld.Id ?? 0,
UploaderId = this.dalamud.ClientState.LocalContentId.ToString(), UploaderId = this.dalamud.ClientState.LocalContentId.ToString(),
@ -133,26 +140,35 @@ namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders
}, },
}; };
client.Headers.Add(HttpRequestHeader.ContentType, "application/json"); var taxPath = "/upload";
var taxUpload = JsonConvert.SerializeObject(taxUploadObject);
Log.Verbose($"{taxPath}: {taxUpload}");
var historyUpload = JsonConvert.SerializeObject(taxRatesRequest); client.PostAsync($"{ApiBase}{taxPath}/{ApiKey}", new StringContent(taxUpload, Encoding.UTF8, "application/json")).GetAwaiter().GetResult();
Log.Verbose(historyUpload);
client.UploadString(ApiBase + $"/upload/{ApiKey}", "POST", historyUpload); // ====================================================================================
Log.Verbose("Universalis tax upload completed."); Log.Verbose("Universalis tax upload completed.");
} }
/// <inheritdoc/> /// <inheritdoc/>
/// <remarks>
/// It may seem backwards that an upload only performs a delete request, however this is not trying
/// to track the available listings, that is done via the listings packet. All this does is remove
/// a listing, or delete it, when a purchase has been made.
/// </remarks>
public void UploadPurchase(MarketBoardPurchaseHandler purchaseHandler) public void UploadPurchase(MarketBoardPurchaseHandler purchaseHandler)
{ {
using var client = new WebClient(); using var client = new HttpClient();
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
client.Headers.Add(HttpRequestHeader.Authorization, ApiKey); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(ApiKey);
var itemId = purchaseHandler.CatalogId; var itemId = purchaseHandler.CatalogId;
var worldId = this.dalamud.ClientState.LocalPlayer?.CurrentWorld.Id ?? 0; var worldId = this.dalamud.ClientState.LocalPlayer?.CurrentWorld.Id ?? 0;
var purchaseRequest = new UniversalisItemListingDeleteRequest // ====================================================================================
var deleteListingObject = new UniversalisItemListingDeleteRequest
{ {
PricePerUnit = purchaseHandler.PricePerUnit, PricePerUnit = purchaseHandler.PricePerUnit,
Quantity = purchaseHandler.ItemQuantity, Quantity = purchaseHandler.ItemQuantity,
@ -161,11 +177,13 @@ namespace Dalamud.Game.Network.Universalis.MarketBoardUploaders
UploaderId = this.dalamud.ClientState.LocalContentId.ToString(), UploaderId = this.dalamud.ClientState.LocalContentId.ToString(),
}; };
var requestPath = ApiBase + $"/api/{worldId}/{itemId}/delete"; var deletePath = $"/api/{worldId}/{itemId}/delete";
var purchaseUpload = JsonConvert.SerializeObject(purchaseRequest); var deleteListing = JsonConvert.SerializeObject(deleteListingObject);
Log.Verbose($"Making request to {requestPath}"); Log.Verbose($"{deletePath}: {deleteListing}");
Log.Verbose(purchaseUpload);
client.UploadString(requestPath, "POST", purchaseUpload); client.PostAsync($"{ApiBase}{deletePath}", new StringContent(deleteListing, Encoding.UTF8, "application/json")).GetAwaiter().GetResult();
// ====================================================================================
Log.Verbose("Universalis purchase upload completed."); Log.Verbose("Universalis purchase upload completed.");
} }

View file

@ -5,14 +5,13 @@ using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Game.Internal.Network; using Dalamud.Game.Network.Internal.MarketBoardUploaders;
using Dalamud.Game.Network.MarketBoardUploaders; using Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis;
using Dalamud.Game.Network.Structures; using Dalamud.Game.Network.Structures;
using Dalamud.Game.Network.Universalis.MarketBoardUploaders;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using Serilog; using Serilog;
namespace Dalamud.Game.Network namespace Dalamud.Game.Network.Internal
{ {
/// <summary> /// <summary>
/// This class handles network notifications and uploading market board data. /// This class handles network notifications and uploading market board data.
@ -141,7 +140,7 @@ namespace Dalamud.Game.Network
var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone); var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone);
if (request == null) if (request == default)
{ {
Log.Error($"Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}"); Log.Error($"Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}");
return; return;
@ -207,17 +206,15 @@ namespace Dalamud.Game.Network
var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId); var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId);
if (request == null) if (request == default)
{ {
Log.Error( Log.Error($"Market Board data arrived without a corresponding request: item#{listing.CatalogId}");
$"Market Board data arrived without a corresponding request: item#{listing.CatalogId}");
return; return;
} }
if (request.ListingsRequestId != -1) if (request.ListingsRequestId != -1)
{ {
Log.Error( Log.Error($"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
$"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
return; return;
} }
@ -243,6 +240,7 @@ namespace Dalamud.Game.Network
if (opCode == this.dalamud.Data.ServerOpCodes["MarketTaxRates"]) if (opCode == this.dalamud.Data.ServerOpCodes["MarketTaxRates"])
{ {
var category = (uint)Marshal.ReadInt32(dataPtr); var category = (uint)Marshal.ReadInt32(dataPtr);
// Result dialog packet does not contain market tax rates // Result dialog packet does not contain market tax rates
if (category != 720905) if (category != 720905)
{ {
@ -279,9 +277,9 @@ namespace Dalamud.Game.Network
// Transaction succeeded // Transaction succeeded
if (purchase.ItemQuantity == this.marketBoardPurchaseHandler.ItemQuantity if (purchase.ItemQuantity == this.marketBoardPurchaseHandler.ItemQuantity
&& (purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId && (purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId
|| purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId + 1000000)) || purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId + 1_000_000))
{ // HQ { // HQ
Log.Information("Bought " + purchase.ItemQuantity + "x " + this.marketBoardPurchaseHandler.CatalogId + " for " + (this.marketBoardPurchaseHandler.PricePerUnit * purchase.ItemQuantity) + " gils, listing id is " + this.marketBoardPurchaseHandler.ListingId); Log.Verbose($"Bought {purchase.ItemQuantity}x {this.marketBoardPurchaseHandler.CatalogId} for {this.marketBoardPurchaseHandler.PricePerUnit * purchase.ItemQuantity} gils, listing id is {this.marketBoardPurchaseHandler.ListingId}");
var handler = this.marketBoardPurchaseHandler; // Capture the object so that we don't pass in a null one when the task starts. var handler = this.marketBoardPurchaseHandler; // Capture the object so that we don't pass in a null one when the task starts.
Task.Run(() => this.uploader.UploadPurchase(handler)); Task.Run(() => this.uploader.UploadPurchase(handler));
} }

View file

@ -1,21 +0,0 @@
using System.Collections.Generic;
using Dalamud.Game.Network.Structures;
namespace Dalamud.Game.Network
{
internal class MarketBoardItemRequest
{
public uint CatalogId { get; set; }
public byte AmountToArrive { get; set; }
public List<MarketBoardCurrentOfferings.MarketBoardItemListing> Listings { get; set; }
public List<MarketBoardHistory.MarketBoardHistoryListing> History { get; set; }
public int ListingsRequestId { get; set; } = -1;
public bool IsDone => this.Listings.Count == this.AmountToArrive && this.History.Count != 0;
}
}

View file

@ -1,4 +1,4 @@
namespace Dalamud.Game.Internal.Network namespace Dalamud.Game.Network
{ {
/// <summary> /// <summary>
/// This represents the direction of a network message. /// This represents the direction of a network message.

View file

@ -5,14 +5,43 @@ using System.Text;
namespace Dalamud.Game.Network.Structures namespace Dalamud.Game.Network.Structures
{ {
/// <summary>
/// This class represents the current market board offerings from a game network packet.
/// </summary>
public class MarketBoardCurrentOfferings public class MarketBoardCurrentOfferings
{ {
public List<MarketBoardItemListing> ItemListings; /// <summary>
/// Initializes a new instance of the <see cref="MarketBoardCurrentOfferings"/> class.
/// </summary>
internal MarketBoardCurrentOfferings()
{
}
public int ListingIndexEnd; /// <summary>
public int ListingIndexStart; /// Gets the list of individual item listings.
public int RequestId; /// </summary>
public List<MarketBoardItemListing> ItemListings { get; internal set; }
/// <summary>
/// Gets the listing end index.
/// </summary>
public int ListingIndexEnd { get; internal set; }
/// <summary>
/// Gets the listing start index.
/// </summary>
public int ListingIndexStart { get; internal set; }
/// <summary>
/// Gets the request ID.
/// </summary>
public int RequestId { get; internal set; }
/// <summary>
/// Read a <see cref="MarketBoardCurrentOfferings"/> object from memory.
/// </summary>
/// <param name="dataPtr">Address to read.</param>
/// <returns>A new <see cref="MarketBoardCurrentOfferings"/> object.</returns>
public static unsafe MarketBoardCurrentOfferings Read(IntPtr dataPtr) public static unsafe MarketBoardCurrentOfferings Read(IntPtr dataPtr)
{ {
var output = new MarketBoardCurrentOfferings(); var output = new MarketBoardCurrentOfferings();
@ -80,32 +109,124 @@ namespace Dalamud.Game.Network.Structures
return output; return output;
} }
/// <summary>
/// This class represents the current market board offering of a single item from the <see cref="MarketBoardCurrentOfferings"/> network packet.
/// </summary>
public class MarketBoardItemListing public class MarketBoardItemListing
{ {
public ulong ArtisanId; /// <summary>
public uint CatalogId; /// Initializes a new instance of the <see cref="MarketBoardItemListing"/> class.
public bool IsHq; /// </summary>
public uint ItemQuantity; internal MarketBoardItemListing()
public DateTime LastReviewTime; {
public ulong ListingId; }
public List<ItemMateria> Materia; /// <summary>
public int MateriaCount; /// Gets the artisan ID.
public bool OnMannequin; /// </summary>
public string PlayerName; public ulong ArtisanId { get; internal set; }
public uint PricePerUnit;
public int RetainerCityId;
public ulong RetainerId;
public string RetainerName; /// <summary>
public ulong RetainerOwnerId; /// Gets the catalog ID.
public int StainId; /// </summary>
public uint TotalTax; public uint CatalogId { get; internal set; }
/// <summary>
/// Gets a value indicating whether the item is HQ.
/// </summary>
public bool IsHq { get; internal set; }
/// <summary>
/// Gets the item quantity.
/// </summary>
public uint ItemQuantity { get; internal set; }
/// <summary>
/// Gets the time this offering was last reviewed.
/// </summary>
public DateTime LastReviewTime { get; internal set; }
/// <summary>
/// Gets the listing ID.
/// </summary>
public ulong ListingId { get; internal set; }
/// <summary>
/// Gets the list of materia attached to this item.
/// </summary>
public List<ItemMateria> Materia { get; internal set; }
/// <summary>
/// Gets the amount of attached materia.
/// </summary>
public int MateriaCount { get; internal set; }
/// <summary>
/// Gets a value indicating whether this item is on a mannequin.
/// </summary>
public bool OnMannequin { get; internal set; }
/// <summary>
/// Gets the player name.
/// </summary>
public string PlayerName { get; internal set; }
/// <summary>
/// Gets the price per unit.
/// </summary>
public uint PricePerUnit { get; internal set; }
/// <summary>
/// Gets the city ID of the retainer selling the item.
/// </summary>
public int RetainerCityId { get; internal set; }
/// <summary>
/// Gets the ID of the retainer selling the item.
/// </summary>
public ulong RetainerId { get; internal set; }
/// <summary>
/// Gets the name of the retainer.
/// </summary>
public string RetainerName { get; internal set; }
/// <summary>
/// Gets the ID of the retainer's owner.
/// </summary>
public ulong RetainerOwnerId { get; internal set; }
/// <summary>
/// Gets the stain or applied dye of the item.
/// </summary>
public int StainId { get; internal set; }
/// <summary>
/// Gets the total tax.
/// </summary>
public uint TotalTax { get; internal set; }
/// <summary>
/// This represents the materia slotted to an <see cref="MarketBoardItemListing"/>.
/// </summary>
public class ItemMateria public class ItemMateria
{ {
public int Index; /// <summary>
public int MateriaId; /// Initializes a new instance of the <see cref="ItemMateria"/> class.
/// </summary>
internal ItemMateria()
{
}
/// <summary>
/// Gets the materia index.
/// </summary>
public int Index { get; internal set; }
/// <summary>
/// Gets the materia ID.
/// </summary>
public int MateriaId { get; internal set; }
} }
} }
} }

View file

@ -5,13 +5,38 @@ using System.Text;
namespace Dalamud.Game.Network.Structures namespace Dalamud.Game.Network.Structures
{ {
/// <summary>
/// This class represents the market board history from a game network packet.
/// </summary>
public class MarketBoardHistory public class MarketBoardHistory
{ {
public uint CatalogId; /// <summary>
public uint CatalogId2; /// Initializes a new instance of the <see cref="MarketBoardHistory"/> class.
/// </summary>
internal MarketBoardHistory()
{
}
public List<MarketBoardHistoryListing> HistoryListings; /// <summary>
/// Gets the catalog ID.
/// </summary>
public uint CatalogId { get; internal set; }
/// <summary>
/// Gets the second catalog ID.
/// </summary>
public uint CatalogId2 { get; internal set; }
/// <summary>
/// Gets the list of individual item history listings.
/// </summary>
public List<MarketBoardHistoryListing> HistoryListings { get; internal set; }
/// <summary>
/// Read a <see cref="MarketBoardHistory"/> object from memory.
/// </summary>
/// <param name="dataPtr">Address to read.</param>
/// <returns>A new <see cref="MarketBoardHistory"/> object.</returns>
public static unsafe MarketBoardHistory Read(IntPtr dataPtr) public static unsafe MarketBoardHistory Read(IntPtr dataPtr)
{ {
var output = new MarketBoardHistory(); var output = new MarketBoardHistory();
@ -47,16 +72,52 @@ namespace Dalamud.Game.Network.Structures
return output; return output;
} }
/// <summary>
/// This class represents the market board history of a single item from the <see cref="MarketBoardHistory"/> network packet.
/// </summary>
public class MarketBoardHistoryListing public class MarketBoardHistoryListing
{ {
public string BuyerName; /// <summary>
/// Initializes a new instance of the <see cref="MarketBoardHistoryListing"/> class.
/// </summary>
internal MarketBoardHistoryListing()
{
}
public uint CatalogId; /// <summary>
public bool IsHq; /// Gets the buyer's name.
public bool OnMannequin; /// </summary>
public DateTime PurchaseTime; public string BuyerName { get; internal set; }
public uint Quantity;
public uint SalePrice; /// <summary>
/// Gets the catalog ID.
/// </summary>
public uint CatalogId { get; internal set; }
/// <summary>
/// Gets a value indicating whether the item is HQ.
/// </summary>
public bool IsHq { get; internal set; }
/// <summary>
/// Gets a value indicating whether the item is on a mannequin.
/// </summary>
public bool OnMannequin { get; internal set; }
/// <summary>
/// Gets the time of purchase.
/// </summary>
public DateTime PurchaseTime { get; internal set; }
/// <summary>
/// Gets the quantity.
/// </summary>
public uint Quantity { get; internal set; }
/// <summary>
/// Gets the sale price.
/// </summary>
public uint SalePrice { get; internal set; }
} }
} }
} }

View file

@ -3,15 +3,53 @@ using System.IO;
namespace Dalamud.Game.Network.Structures namespace Dalamud.Game.Network.Structures
{ {
/// <summary>
/// This class represents the market tax rates from a game network packet.
/// </summary>
public class MarketTaxRates public class MarketTaxRates
{ {
public uint LimsaLominsaTax; /// <summary>
public uint GridaniaTax; /// Initializes a new instance of the <see cref="MarketTaxRates"/> class.
public uint UldahTax; /// </summary>
public uint IshgardTax; internal MarketTaxRates()
public uint KuganeTax; {
public uint CrystariumTax; }
/// <summary>
/// Gets the tax rate in Limsa Lominsa.
/// </summary>
public uint LimsaLominsaTax { get; internal set; }
/// <summary>
/// Gets the tax rate in Gridania.
/// </summary>
public uint GridaniaTax { get; internal set; }
/// <summary>
/// Gets the tax rate in Ul'dah.
/// </summary>
public uint UldahTax { get; internal set; }
/// <summary>
/// Gets the tax rate in Ishgard.
/// </summary>
public uint IshgardTax { get; internal set; }
/// <summary>
/// Gets the tax rate in Kugane.
/// </summary>
public uint KuganeTax { get; internal set; }
/// <summary>
/// Gets the tax rate in the Crystarium.
/// </summary>
public uint CrystariumTax { get; internal set; }
/// <summary>
/// Read a <see cref="MarketTaxRates"/> object from memory.
/// </summary>
/// <param name="dataPtr">Address to read.</param>
/// <returns>A new <see cref="MarketTaxRates"/> object.</returns>
public static unsafe MarketTaxRates Read(IntPtr dataPtr) public static unsafe MarketTaxRates Read(IntPtr dataPtr)
{ {
var output = new MarketTaxRates(); var output = new MarketTaxRates();