mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-01-02 05:43:40 +01:00
Revert "refactor(Dalamud): switch to file-scoped namespaces"
This reverts commit b5f34c3199.
This commit is contained in:
parent
d473826247
commit
1561fbac00
325 changed files with 45549 additions and 45209 deletions
|
|
@ -7,178 +7,179 @@ using Dalamud.IoC;
|
|||
using Dalamud.IoC.Internal;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Network;
|
||||
|
||||
/// <summary>
|
||||
/// This class handles interacting with game network events.
|
||||
/// </summary>
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
public sealed class GameNetwork : IDisposable
|
||||
namespace Dalamud.Game.Network
|
||||
{
|
||||
private readonly GameNetworkAddressResolver address;
|
||||
private readonly Hook<ProcessZonePacketDownDelegate> processZonePacketDownHook;
|
||||
private readonly Hook<ProcessZonePacketUpDelegate> processZonePacketUpHook;
|
||||
private readonly Queue<byte[]> zoneInjectQueue = new();
|
||||
|
||||
private IntPtr baseAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameNetwork"/> class.
|
||||
/// This class handles interacting with game network events.
|
||||
/// </summary>
|
||||
internal GameNetwork()
|
||||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
public sealed class GameNetwork : IDisposable
|
||||
{
|
||||
this.address = new GameNetworkAddressResolver();
|
||||
this.address.Setup();
|
||||
private readonly GameNetworkAddressResolver address;
|
||||
private readonly Hook<ProcessZonePacketDownDelegate> processZonePacketDownHook;
|
||||
private readonly Hook<ProcessZonePacketUpDelegate> processZonePacketUpHook;
|
||||
private readonly Queue<byte[]> zoneInjectQueue = new();
|
||||
|
||||
Log.Verbose("===== G A M E N E T W O R K =====");
|
||||
Log.Verbose($"ProcessZonePacketDown address 0x{this.address.ProcessZonePacketDown.ToInt64():X}");
|
||||
Log.Verbose($"ProcessZonePacketUp address 0x{this.address.ProcessZonePacketUp.ToInt64():X}");
|
||||
private IntPtr baseAddress;
|
||||
|
||||
this.processZonePacketDownHook = new Hook<ProcessZonePacketDownDelegate>(this.address.ProcessZonePacketDown, this.ProcessZonePacketDownDetour);
|
||||
this.processZonePacketUpHook = new Hook<ProcessZonePacketUpDelegate>(this.address.ProcessZonePacketUp, this.ProcessZonePacketUpDetour);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The delegate type of a network message event.
|
||||
/// </summary>
|
||||
/// <param name="dataPtr">The pointer to the raw data.</param>
|
||||
/// <param name="opCode">The operation ID code.</param>
|
||||
/// <param name="sourceActorId">The source actor ID.</param>
|
||||
/// <param name="targetActorId">The taret actor ID.</param>
|
||||
/// <param name="direction">The direction of the packed.</param>
|
||||
public delegate void OnNetworkMessageDelegate(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate void ProcessZonePacketDownDelegate(IntPtr a, uint targetId, IntPtr dataPtr);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate byte ProcessZonePacketUpDelegate(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4);
|
||||
|
||||
/// <summary>
|
||||
/// Event that is called when a network message is sent/received.
|
||||
/// </summary>
|
||||
public event OnNetworkMessageDelegate NetworkMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Enable this module.
|
||||
/// </summary>
|
||||
public void Enable()
|
||||
{
|
||||
this.processZonePacketDownHook.Enable();
|
||||
this.processZonePacketUpHook.Enable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.processZonePacketDownHook.Dispose();
|
||||
this.processZonePacketUpHook.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a chat queue.
|
||||
/// </summary>
|
||||
internal void UpdateQueue()
|
||||
{
|
||||
while (this.zoneInjectQueue.Count > 0)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameNetwork"/> class.
|
||||
/// </summary>
|
||||
internal GameNetwork()
|
||||
{
|
||||
var packetData = this.zoneInjectQueue.Dequeue();
|
||||
this.address = new GameNetworkAddressResolver();
|
||||
this.address.Setup();
|
||||
|
||||
var unmanagedPacketData = Marshal.AllocHGlobal(packetData.Length);
|
||||
Marshal.Copy(packetData, 0, unmanagedPacketData, packetData.Length);
|
||||
Log.Verbose("===== G A M E N E T W O R K =====");
|
||||
Log.Verbose($"ProcessZonePacketDown address 0x{this.address.ProcessZonePacketDown.ToInt64():X}");
|
||||
Log.Verbose($"ProcessZonePacketUp address 0x{this.address.ProcessZonePacketUp.ToInt64():X}");
|
||||
|
||||
if (this.baseAddress != IntPtr.Zero)
|
||||
this.processZonePacketDownHook = new Hook<ProcessZonePacketDownDelegate>(this.address.ProcessZonePacketDown, this.ProcessZonePacketDownDetour);
|
||||
this.processZonePacketUpHook = new Hook<ProcessZonePacketUpDelegate>(this.address.ProcessZonePacketUp, this.ProcessZonePacketUpDetour);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The delegate type of a network message event.
|
||||
/// </summary>
|
||||
/// <param name="dataPtr">The pointer to the raw data.</param>
|
||||
/// <param name="opCode">The operation ID code.</param>
|
||||
/// <param name="sourceActorId">The source actor ID.</param>
|
||||
/// <param name="targetActorId">The taret actor ID.</param>
|
||||
/// <param name="direction">The direction of the packed.</param>
|
||||
public delegate void OnNetworkMessageDelegate(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate void ProcessZonePacketDownDelegate(IntPtr a, uint targetId, IntPtr dataPtr);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
private delegate byte ProcessZonePacketUpDelegate(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4);
|
||||
|
||||
/// <summary>
|
||||
/// Event that is called when a network message is sent/received.
|
||||
/// </summary>
|
||||
public event OnNetworkMessageDelegate NetworkMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Enable this module.
|
||||
/// </summary>
|
||||
public void Enable()
|
||||
{
|
||||
this.processZonePacketDownHook.Enable();
|
||||
this.processZonePacketUpHook.Enable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.processZonePacketDownHook.Dispose();
|
||||
this.processZonePacketUpHook.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process a chat queue.
|
||||
/// </summary>
|
||||
internal void UpdateQueue()
|
||||
{
|
||||
while (this.zoneInjectQueue.Count > 0)
|
||||
{
|
||||
this.processZonePacketDownHook.Original(this.baseAddress, 0, unmanagedPacketData);
|
||||
var packetData = this.zoneInjectQueue.Dequeue();
|
||||
|
||||
var unmanagedPacketData = Marshal.AllocHGlobal(packetData.Length);
|
||||
Marshal.Copy(packetData, 0, unmanagedPacketData, packetData.Length);
|
||||
|
||||
if (this.baseAddress != IntPtr.Zero)
|
||||
{
|
||||
this.processZonePacketDownHook.Original(this.baseAddress, 0, unmanagedPacketData);
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(unmanagedPacketData);
|
||||
}
|
||||
|
||||
Marshal.FreeHGlobal(unmanagedPacketData);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessZonePacketDownDetour(IntPtr a, uint targetId, IntPtr dataPtr)
|
||||
{
|
||||
this.baseAddress = a;
|
||||
|
||||
// Go back 0x10 to get back to the start of the packet header
|
||||
dataPtr -= 0x10;
|
||||
|
||||
try
|
||||
private void ProcessZonePacketDownDetour(IntPtr a, uint targetId, IntPtr dataPtr)
|
||||
{
|
||||
// Call events
|
||||
this.NetworkMessage?.Invoke(dataPtr + 0x20, (ushort)Marshal.ReadInt16(dataPtr, 0x12), 0, targetId, NetworkMessageDirection.ZoneDown);
|
||||
this.baseAddress = a;
|
||||
|
||||
// Go back 0x10 to get back to the start of the packet header
|
||||
dataPtr -= 0x10;
|
||||
|
||||
this.processZonePacketDownHook.Original(a, targetId, dataPtr + 0x10);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string header;
|
||||
try
|
||||
{
|
||||
var data = new byte[32];
|
||||
Marshal.Copy(dataPtr, data, 0, 32);
|
||||
header = BitConverter.ToString(data);
|
||||
// Call events
|
||||
this.NetworkMessage?.Invoke(dataPtr + 0x20, (ushort)Marshal.ReadInt16(dataPtr, 0x12), 0, targetId, NetworkMessageDirection.ZoneDown);
|
||||
|
||||
this.processZonePacketDownHook.Original(a, targetId, dataPtr + 0x10);
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
header = "failed";
|
||||
string header;
|
||||
try
|
||||
{
|
||||
var data = new byte[32];
|
||||
Marshal.Copy(dataPtr, data, 0, 32);
|
||||
header = BitConverter.ToString(data);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
header = "failed";
|
||||
}
|
||||
|
||||
Log.Error(ex, "Exception on ProcessZonePacketDown hook. Header: " + header);
|
||||
|
||||
this.processZonePacketDownHook.Original(a, targetId, dataPtr + 0x10);
|
||||
}
|
||||
|
||||
Log.Error(ex, "Exception on ProcessZonePacketDown hook. Header: " + header);
|
||||
|
||||
this.processZonePacketDownHook.Original(a, targetId, dataPtr + 0x10);
|
||||
}
|
||||
}
|
||||
|
||||
private byte ProcessZonePacketUpDetour(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4)
|
||||
{
|
||||
try
|
||||
private byte ProcessZonePacketUpDetour(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4)
|
||||
{
|
||||
// Call events
|
||||
// TODO: Implement actor IDs
|
||||
this.NetworkMessage?.Invoke(dataPtr + 0x20, (ushort)Marshal.ReadInt16(dataPtr), 0x0, 0x0, NetworkMessageDirection.ZoneUp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string header;
|
||||
try
|
||||
{
|
||||
var data = new byte[32];
|
||||
Marshal.Copy(dataPtr, data, 0, 32);
|
||||
header = BitConverter.ToString(data);
|
||||
// Call events
|
||||
// TODO: Implement actor IDs
|
||||
this.NetworkMessage?.Invoke(dataPtr + 0x20, (ushort)Marshal.ReadInt16(dataPtr), 0x0, 0x0, NetworkMessageDirection.ZoneUp);
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
header = "failed";
|
||||
string header;
|
||||
try
|
||||
{
|
||||
var data = new byte[32];
|
||||
Marshal.Copy(dataPtr, data, 0, 32);
|
||||
header = BitConverter.ToString(data);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
header = "failed";
|
||||
}
|
||||
|
||||
Log.Error(ex, "Exception on ProcessZonePacketUp hook. Header: " + header);
|
||||
}
|
||||
|
||||
Log.Error(ex, "Exception on ProcessZonePacketUp hook. Header: " + header);
|
||||
return this.processZonePacketUpHook.Original(a1, dataPtr, a3, a4);
|
||||
}
|
||||
|
||||
return this.processZonePacketUpHook.Original(a1, dataPtr, a3, a4);
|
||||
// private void InjectZoneProtoPacket(byte[] data)
|
||||
// {
|
||||
// this.zoneInjectQueue.Enqueue(data);
|
||||
// }
|
||||
|
||||
// private void InjectActorControl(short cat, int param1)
|
||||
// {
|
||||
// var packetData = new byte[]
|
||||
// {
|
||||
// 0x14, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x17, 0x7C, 0xC5, 0x5D, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x05, 0x00, 0x48, 0xB2, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x43, 0x7F, 0x00, 0x00,
|
||||
// };
|
||||
//
|
||||
// BitConverter.GetBytes((short)cat).CopyTo(packetData, 0x10);
|
||||
//
|
||||
// BitConverter.GetBytes((uint)param1).CopyTo(packetData, 0x14);
|
||||
//
|
||||
// this.InjectZoneProtoPacket(packetData);
|
||||
// }
|
||||
}
|
||||
|
||||
// private void InjectZoneProtoPacket(byte[] data)
|
||||
// {
|
||||
// this.zoneInjectQueue.Enqueue(data);
|
||||
// }
|
||||
|
||||
// private void InjectActorControl(short cat, int param1)
|
||||
// {
|
||||
// var packetData = new byte[]
|
||||
// {
|
||||
// 0x14, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x17, 0x7C, 0xC5, 0x5D, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x05, 0x00, 0x48, 0xB2, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0x43, 0x7F, 0x00, 0x00,
|
||||
// };
|
||||
//
|
||||
// BitConverter.GetBytes((short)cat).CopyTo(packetData, 0x10);
|
||||
//
|
||||
// BitConverter.GetBytes((uint)param1).CopyTo(packetData, 0x14);
|
||||
//
|
||||
// this.InjectZoneProtoPacket(packetData);
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,31 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Network;
|
||||
using Dalamud.Game.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// The address resolver for the <see cref="GameNetwork"/> class.
|
||||
/// </summary>
|
||||
public sealed class GameNetworkAddressResolver : BaseAddressResolver
|
||||
namespace Dalamud.Game.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the ProcessZonePacketDown method.
|
||||
/// The address resolver for the <see cref="GameNetwork"/> class.
|
||||
/// </summary>
|
||||
public IntPtr ProcessZonePacketDown { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the ProcessZonePacketUp method.
|
||||
/// </summary>
|
||||
public IntPtr ProcessZonePacketUp { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Setup64Bit(SigScanner sig)
|
||||
public sealed class GameNetworkAddressResolver : BaseAddressResolver
|
||||
{
|
||||
// ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 7A FF 0F B7 57 02 8D 42 89 3D 5F 02 00 00 0F 87 60 01 00 00 4C 8D 05");
|
||||
// ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 73 FF 0F B7 57 02 8D 42 ?? 3D ?? ?? 00 00 0F 87 60 01 00 00 4C 8D 05");
|
||||
this.ProcessZonePacketDown = sig.ScanText("48 89 5C 24 ?? 56 48 83 EC 50 8B F2");
|
||||
this.ProcessZonePacketUp = sig.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC 70 8B 81 ?? ?? ?? ??");
|
||||
/// <summary>
|
||||
/// Gets the address of the ProcessZonePacketDown method.
|
||||
/// </summary>
|
||||
public IntPtr ProcessZonePacketDown { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the ProcessZonePacketUp method.
|
||||
/// </summary>
|
||||
public IntPtr ProcessZonePacketUp { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Setup64Bit(SigScanner sig)
|
||||
{
|
||||
// ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 7A FF 0F B7 57 02 8D 42 89 3D 5F 02 00 00 0F 87 60 01 00 00 4C 8D 05");
|
||||
// ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 73 FF 0F B7 57 02 8D 42 ?? 3D ?? ?? 00 00 0F 87 60 01 00 00 4C 8D 05");
|
||||
this.ProcessZonePacketDown = sig.ScanText("48 89 5C 24 ?? 56 48 83 EC 50 8B F2");
|
||||
this.ProcessZonePacketUp = sig.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC 70 8B 81 ?? ?? ?? ??");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,31 +2,32 @@ using System.Threading.Tasks;
|
|||
|
||||
using Dalamud.Game.Network.Structures;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders;
|
||||
|
||||
/// <summary>
|
||||
/// An interface binding for the Universalis uploader.
|
||||
/// </summary>
|
||||
internal interface IMarketBoardUploader
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders
|
||||
{
|
||||
/// <summary>
|
||||
/// Upload data about an item.
|
||||
/// An interface binding for the Universalis uploader.
|
||||
/// </summary>
|
||||
/// <param name="item">The item request data being uploaded.</param>
|
||||
/// <returns>An async task.</returns>
|
||||
Task Upload(MarketBoardItemRequest item);
|
||||
internal interface IMarketBoardUploader
|
||||
{
|
||||
/// <summary>
|
||||
/// Upload data about an item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item request data being uploaded.</param>
|
||||
/// <returns>An async task.</returns>
|
||||
Task Upload(MarketBoardItemRequest item);
|
||||
|
||||
/// <summary>
|
||||
/// Upload tax rate data.
|
||||
/// </summary>
|
||||
/// <param name="taxRates">The tax rate data being uploaded.</param>
|
||||
/// <returns>An async task.</returns>
|
||||
Task UploadTax(MarketTaxRates taxRates);
|
||||
/// <summary>
|
||||
/// Upload tax rate data.
|
||||
/// </summary>
|
||||
/// <param name="taxRates">The tax rate data being uploaded.</param>
|
||||
/// <returns>An async task.</returns>
|
||||
Task UploadTax(MarketTaxRates taxRates);
|
||||
|
||||
/// <summary>
|
||||
/// Upload information about a purchase this client has made.
|
||||
/// </summary>
|
||||
/// <param name="purchaseHandler">The purchase handler data associated with the sale.</param>
|
||||
/// <returns>An async task.</returns>
|
||||
Task UploadPurchase(MarketBoardPurchaseHandler purchaseHandler);
|
||||
/// <summary>
|
||||
/// Upload information about a purchase this client has made.
|
||||
/// </summary>
|
||||
/// <param name="purchaseHandler">The purchase handler data associated with the sale.</param>
|
||||
/// <returns>An async task.</returns>
|
||||
Task UploadPurchase(MarketBoardPurchaseHandler purchaseHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,63 +4,64 @@ using System.IO;
|
|||
|
||||
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
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders
|
||||
{
|
||||
private MarketBoardItemRequest()
|
||||
/// <summary>
|
||||
/// This represents a submission to a marketboard aggregation website.
|
||||
/// </summary>
|
||||
internal class MarketBoardItemRequest
|
||||
{
|
||||
}
|
||||
private MarketBoardItemRequest()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the catalog ID.
|
||||
/// </summary>
|
||||
public uint CatalogId { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the catalog ID.
|
||||
/// </summary>
|
||||
public uint CatalogId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount to arrive.
|
||||
/// </summary>
|
||||
public byte AmountToArrive { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the amount to arrive.
|
||||
/// </summary>
|
||||
public byte AmountToArrive { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the offered item listings.
|
||||
/// </summary>
|
||||
public List<MarketBoardCurrentOfferings.MarketBoardItemListing> Listings { get; } = new();
|
||||
/// <summary>
|
||||
/// Gets the offered item listings.
|
||||
/// </summary>
|
||||
public List<MarketBoardCurrentOfferings.MarketBoardItemListing> Listings { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the historical item listings.
|
||||
/// </summary>
|
||||
public List<MarketBoardHistory.MarketBoardHistoryListing> History { get; } = new();
|
||||
/// <summary>
|
||||
/// Gets the historical item listings.
|
||||
/// </summary>
|
||||
public List<MarketBoardHistory.MarketBoardHistoryListing> History { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the listing request ID.
|
||||
/// </summary>
|
||||
public int ListingsRequestId { get; set; } = -1;
|
||||
/// <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;
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the upload is complete.
|
||||
/// </summary>
|
||||
public bool IsDone => this.Listings.Count == this.AmountToArrive && this.History.Count != 0;
|
||||
|
||||
/// <summary>
|
||||
/// Read a packet off the wire.
|
||||
/// </summary>
|
||||
/// <param name="dataPtr">Packet data.</param>
|
||||
/// <returns>An object representing the data read.</returns>
|
||||
public static unsafe MarketBoardItemRequest Read(IntPtr dataPtr)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
/// <summary>
|
||||
/// Read a packet off the wire.
|
||||
/// </summary>
|
||||
/// <param name="dataPtr">Packet data.</param>
|
||||
/// <returns>An object representing the data read.</returns>
|
||||
public static unsafe MarketBoardItemRequest Read(IntPtr dataPtr)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
var output = new MarketBoardItemRequest();
|
||||
var output = new MarketBoardItemRequest();
|
||||
|
||||
output.CatalogId = reader.ReadUInt32();
|
||||
stream.Position += 0x7;
|
||||
output.AmountToArrive = reader.ReadByte();
|
||||
output.CatalogId = reader.ReadUInt32();
|
||||
stream.Position += 0x7;
|
||||
output.AmountToArrive = reader.ReadByte();
|
||||
|
||||
return output;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,58 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types;
|
||||
|
||||
/// <summary>
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
internal class UniversalisHistoryEntry
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the item is HQ or not.
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
[JsonProperty("hq")]
|
||||
public bool Hq { get; set; }
|
||||
internal class UniversalisHistoryEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the item is HQ or not.
|
||||
/// </summary>
|
||||
[JsonProperty("hq")]
|
||||
public bool Hq { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item price per unit.
|
||||
/// </summary>
|
||||
[JsonProperty("pricePerUnit")]
|
||||
public uint PricePerUnit { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the item price per unit.
|
||||
/// </summary>
|
||||
[JsonProperty("pricePerUnit")]
|
||||
public uint PricePerUnit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the quantity of items available.
|
||||
/// </summary>
|
||||
[JsonProperty("quantity")]
|
||||
public uint Quantity { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the quantity of items available.
|
||||
/// </summary>
|
||||
[JsonProperty("quantity")]
|
||||
public uint Quantity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the buyer.
|
||||
/// </summary>
|
||||
[JsonProperty("buyerName")]
|
||||
public string BuyerName { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the buyer.
|
||||
/// </summary>
|
||||
[JsonProperty("buyerName")]
|
||||
public string BuyerName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this item was on a mannequin.
|
||||
/// </summary>
|
||||
[JsonProperty("onMannequin")]
|
||||
public bool OnMannequin { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this item was on a mannequin.
|
||||
/// </summary>
|
||||
[JsonProperty("onMannequin")]
|
||||
public bool OnMannequin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the seller ID.
|
||||
/// </summary>
|
||||
[JsonProperty("sellerID")]
|
||||
public string SellerId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the seller ID.
|
||||
/// </summary>
|
||||
[JsonProperty("sellerID")]
|
||||
public string SellerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the buyer ID.
|
||||
/// </summary>
|
||||
[JsonProperty("buyerID")]
|
||||
public string BuyerId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the buyer ID.
|
||||
/// </summary>
|
||||
[JsonProperty("buyerID")]
|
||||
public string BuyerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp of the transaction.
|
||||
/// </summary>
|
||||
[JsonProperty("timestamp")]
|
||||
public long Timestamp { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamp of the transaction.
|
||||
/// </summary>
|
||||
[JsonProperty("timestamp")]
|
||||
public long Timestamp { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,34 +2,35 @@ using System.Collections.Generic;
|
|||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types;
|
||||
|
||||
/// <summary>
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
internal class UniversalisHistoryUploadRequest
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the world ID.
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
[JsonProperty("worldID")]
|
||||
public uint WorldId { get; set; }
|
||||
internal class UniversalisHistoryUploadRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the world ID.
|
||||
/// </summary>
|
||||
[JsonProperty("worldID")]
|
||||
public uint WorldId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item ID.
|
||||
/// </summary>
|
||||
[JsonProperty("itemID")]
|
||||
public uint ItemId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the item ID.
|
||||
/// </summary>
|
||||
[JsonProperty("itemID")]
|
||||
public uint ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of available entries.
|
||||
/// </summary>
|
||||
[JsonProperty("entries")]
|
||||
public List<UniversalisHistoryEntry> Entries { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the list of available entries.
|
||||
/// </summary>
|
||||
[JsonProperty("entries")]
|
||||
public List<UniversalisHistoryEntry> Entries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the uploader ID.
|
||||
/// </summary>
|
||||
[JsonProperty("uploaderID")]
|
||||
public string UploaderId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the uploader ID.
|
||||
/// </summary>
|
||||
[JsonProperty("uploaderID")]
|
||||
public string UploaderId { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,40 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Request payload for market board purchases.
|
||||
/// </summary>
|
||||
internal class UniversalisItemListingDeleteRequest
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the object ID of the retainer associated with the sale.
|
||||
/// Request payload for market board purchases.
|
||||
/// </summary>
|
||||
[JsonProperty("retainerID")]
|
||||
public string RetainerId { get; set; }
|
||||
internal class UniversalisItemListingDeleteRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the object ID of the retainer associated with the sale.
|
||||
/// </summary>
|
||||
[JsonProperty("retainerID")]
|
||||
public string RetainerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the object ID of the item listing.
|
||||
/// </summary>
|
||||
[JsonProperty("listingID")]
|
||||
public string ListingId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the object ID of the item listing.
|
||||
/// </summary>
|
||||
[JsonProperty("listingID")]
|
||||
public string ListingId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the quantity of the item that was purchased.
|
||||
/// </summary>
|
||||
[JsonProperty("quantity")]
|
||||
public uint Quantity { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the quantity of the item that was purchased.
|
||||
/// </summary>
|
||||
[JsonProperty("quantity")]
|
||||
public uint Quantity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the unit price of the item.
|
||||
/// </summary>
|
||||
[JsonProperty("pricePerUnit")]
|
||||
public uint PricePerUnit { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the unit price of the item.
|
||||
/// </summary>
|
||||
[JsonProperty("pricePerUnit")]
|
||||
public uint PricePerUnit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the uploader ID.
|
||||
/// </summary>
|
||||
[JsonProperty("uploaderID")]
|
||||
public string UploaderId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the uploader ID.
|
||||
/// </summary>
|
||||
[JsonProperty("uploaderID")]
|
||||
public string UploaderId { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,94 +2,95 @@ using System.Collections.Generic;
|
|||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types;
|
||||
|
||||
/// <summary>
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
internal class UniversalisItemListingsEntry
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the listing ID.
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
[JsonProperty("listingID")]
|
||||
public string ListingId { get; set; }
|
||||
internal class UniversalisItemListingsEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the listing ID.
|
||||
/// </summary>
|
||||
[JsonProperty("listingID")]
|
||||
public string ListingId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the item is HQ.
|
||||
/// </summary>
|
||||
[JsonProperty("hq")]
|
||||
public bool Hq { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the item is HQ.
|
||||
/// </summary>
|
||||
[JsonProperty("hq")]
|
||||
public bool Hq { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item price per unit.
|
||||
/// </summary>
|
||||
[JsonProperty("pricePerUnit")]
|
||||
public uint PricePerUnit { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the item price per unit.
|
||||
/// </summary>
|
||||
[JsonProperty("pricePerUnit")]
|
||||
public uint PricePerUnit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item quantity.
|
||||
/// </summary>
|
||||
[JsonProperty("quantity")]
|
||||
public uint Quantity { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the item quantity.
|
||||
/// </summary>
|
||||
[JsonProperty("quantity")]
|
||||
public uint Quantity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the retainer selling the item.
|
||||
/// </summary>
|
||||
[JsonProperty("retainerName")]
|
||||
public string RetainerName { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the retainer selling the item.
|
||||
/// </summary>
|
||||
[JsonProperty("retainerName")]
|
||||
public string RetainerName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ID of the retainer selling the item.
|
||||
/// </summary>
|
||||
[JsonProperty("retainerID")]
|
||||
public string RetainerId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the ID of the retainer selling the item.
|
||||
/// </summary>
|
||||
[JsonProperty("retainerID")]
|
||||
public string RetainerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the user who created the entry.
|
||||
/// </summary>
|
||||
[JsonProperty("creatorName")]
|
||||
public string CreatorName { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the user who created the entry.
|
||||
/// </summary>
|
||||
[JsonProperty("creatorName")]
|
||||
public string CreatorName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the item is on a mannequin.
|
||||
/// </summary>
|
||||
[JsonProperty("onMannequin")]
|
||||
public bool OnMannequin { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the item is on a mannequin.
|
||||
/// </summary>
|
||||
[JsonProperty("onMannequin")]
|
||||
public bool OnMannequin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the seller ID.
|
||||
/// </summary>
|
||||
[JsonProperty("sellerID")]
|
||||
public string SellerId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the seller ID.
|
||||
/// </summary>
|
||||
[JsonProperty("sellerID")]
|
||||
public string SellerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ID of the user who created the entry.
|
||||
/// </summary>
|
||||
[JsonProperty("creatorID")]
|
||||
public string CreatorId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the ID of the user who created the entry.
|
||||
/// </summary>
|
||||
[JsonProperty("creatorID")]
|
||||
public string CreatorId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ID of the dye on the item.
|
||||
/// </summary>
|
||||
[JsonProperty("stainID")]
|
||||
public int StainId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the ID of the dye on the item.
|
||||
/// </summary>
|
||||
[JsonProperty("stainID")]
|
||||
public int StainId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the city where the selling retainer resides.
|
||||
/// </summary>
|
||||
[JsonProperty("retainerCity")]
|
||||
public int RetainerCity { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the city where the selling retainer resides.
|
||||
/// </summary>
|
||||
[JsonProperty("retainerCity")]
|
||||
public int RetainerCity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the last time the entry was reviewed.
|
||||
/// </summary>
|
||||
[JsonProperty("lastReviewTime")]
|
||||
public long LastReviewTime { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the last time the entry was reviewed.
|
||||
/// </summary>
|
||||
[JsonProperty("lastReviewTime")]
|
||||
public long LastReviewTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the materia attached to the item.
|
||||
/// </summary>
|
||||
[JsonProperty("materia")]
|
||||
public List<UniversalisItemMateria> Materia { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the materia attached to the item.
|
||||
/// </summary>
|
||||
[JsonProperty("materia")]
|
||||
public List<UniversalisItemMateria> Materia { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,34 +2,35 @@ using System.Collections.Generic;
|
|||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types;
|
||||
|
||||
/// <summary>
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
internal class UniversalisItemListingsUploadRequest
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the world ID.
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
[JsonProperty("worldID")]
|
||||
public uint WorldId { get; set; }
|
||||
internal class UniversalisItemListingsUploadRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the world ID.
|
||||
/// </summary>
|
||||
[JsonProperty("worldID")]
|
||||
public uint WorldId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the item ID.
|
||||
/// </summary>
|
||||
[JsonProperty("itemID")]
|
||||
public uint ItemId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the item ID.
|
||||
/// </summary>
|
||||
[JsonProperty("itemID")]
|
||||
public uint ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of available items.
|
||||
/// </summary>
|
||||
[JsonProperty("listings")]
|
||||
public List<UniversalisItemListingsEntry> Listings { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the list of available items.
|
||||
/// </summary>
|
||||
[JsonProperty("listings")]
|
||||
public List<UniversalisItemListingsEntry> Listings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the uploader ID.
|
||||
/// </summary>
|
||||
[JsonProperty("uploaderID")]
|
||||
public string UploaderId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the uploader ID.
|
||||
/// </summary>
|
||||
[JsonProperty("uploaderID")]
|
||||
public string UploaderId { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,22 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types;
|
||||
|
||||
/// <summary>
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
internal class UniversalisItemMateria
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the item slot ID.
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
[JsonProperty("slotID")]
|
||||
public int SlotId { get; set; }
|
||||
internal class UniversalisItemMateria
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the item slot ID.
|
||||
/// </summary>
|
||||
[JsonProperty("slotID")]
|
||||
public int SlotId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the materia ID.
|
||||
/// </summary>
|
||||
[JsonProperty("materiaID")]
|
||||
public int MateriaId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the materia ID.
|
||||
/// </summary>
|
||||
[JsonProperty("materiaID")]
|
||||
public int MateriaId { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +1,46 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types;
|
||||
|
||||
/// <summary>
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
internal class UniversalisTaxData
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets Limsa Lominsa's current tax rate.
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
[JsonProperty("limsaLominsa")]
|
||||
public uint LimsaLominsa { get; set; }
|
||||
internal class UniversalisTaxData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets Limsa Lominsa's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("limsaLominsa")]
|
||||
public uint LimsaLominsa { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets Gridania's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("gridania")]
|
||||
public uint Gridania { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets Gridania's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("gridania")]
|
||||
public uint Gridania { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets Ul'dah's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("uldah")]
|
||||
public uint Uldah { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets Ul'dah's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("uldah")]
|
||||
public uint Uldah { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets Ishgard's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("ishgard")]
|
||||
public uint Ishgard { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets Ishgard's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("ishgard")]
|
||||
public uint Ishgard { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets Kugane's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("kugane")]
|
||||
public uint Kugane { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets Kugane's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("kugane")]
|
||||
public uint Kugane { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets The Crystarium's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("crystarium")]
|
||||
public uint Crystarium { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets The Crystarium's current tax rate.
|
||||
/// </summary>
|
||||
[JsonProperty("crystarium")]
|
||||
public uint Crystarium { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,28 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types;
|
||||
|
||||
/// <summary>
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
internal class UniversalisTaxUploadRequest
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the uploader's ID.
|
||||
/// A Universalis API structure.
|
||||
/// </summary>
|
||||
[JsonProperty("uploaderID")]
|
||||
public string UploaderId { get; set; }
|
||||
internal class UniversalisTaxUploadRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the uploader's ID.
|
||||
/// </summary>
|
||||
[JsonProperty("uploaderID")]
|
||||
public string UploaderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the world to retrieve data from.
|
||||
/// </summary>
|
||||
[JsonProperty("worldID")]
|
||||
public uint WorldId { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the world to retrieve data from.
|
||||
/// </summary>
|
||||
[JsonProperty("worldID")]
|
||||
public uint WorldId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets tax data for each city's market.
|
||||
/// </summary>
|
||||
[JsonProperty("marketTaxRates")]
|
||||
public UniversalisTaxData TaxData { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets tax data for each city's market.
|
||||
/// </summary>
|
||||
[JsonProperty("marketTaxRates")]
|
||||
public UniversalisTaxData TaxData { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,181 +10,182 @@ using Dalamud.Utility;
|
|||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis;
|
||||
|
||||
/// <summary>
|
||||
/// This class represents an uploader for contributing data to Universalis.
|
||||
/// </summary>
|
||||
internal class UniversalisMarketBoardUploader : IMarketBoardUploader
|
||||
namespace Dalamud.Game.Network.Internal.MarketBoardUploaders.Universalis
|
||||
{
|
||||
private const string ApiBase = "https://universalis.app";
|
||||
// private const string ApiBase = "https://127.0.0.1:443";
|
||||
|
||||
private const string ApiKey = "GGD6RdSfGyRiHM5WDnAo0Nj9Nv7aC5NDhMj3BebT";
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UniversalisMarketBoardUploader"/> class.
|
||||
/// This class represents an uploader for contributing data to Universalis.
|
||||
/// </summary>
|
||||
public UniversalisMarketBoardUploader()
|
||||
internal class UniversalisMarketBoardUploader : IMarketBoardUploader
|
||||
{
|
||||
}
|
||||
private const string ApiBase = "https://universalis.app";
|
||||
// private const string ApiBase = "https://127.0.0.1:443";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task Upload(MarketBoardItemRequest request)
|
||||
{
|
||||
var clientState = Service<ClientState.ClientState>.Get();
|
||||
private const string ApiKey = "GGD6RdSfGyRiHM5WDnAo0Nj9Nv7aC5NDhMj3BebT";
|
||||
|
||||
Log.Verbose("Starting Universalis upload.");
|
||||
var uploader = clientState.LocalContentId;
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
var listingsUploadObject = new UniversalisItemListingsUploadRequest
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UniversalisMarketBoardUploader"/> class.
|
||||
/// </summary>
|
||||
public UniversalisMarketBoardUploader()
|
||||
{
|
||||
WorldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0,
|
||||
UploaderId = uploader.ToString(),
|
||||
ItemId = request.CatalogId,
|
||||
Listings = new List<UniversalisItemListingsEntry>(),
|
||||
};
|
||||
}
|
||||
|
||||
foreach (var marketBoardItemListing in request.Listings)
|
||||
/// <inheritdoc/>
|
||||
public async Task Upload(MarketBoardItemRequest request)
|
||||
{
|
||||
var universalisListing = new UniversalisItemListingsEntry
|
||||
var clientState = Service<ClientState.ClientState>.Get();
|
||||
|
||||
Log.Verbose("Starting Universalis upload.");
|
||||
var uploader = clientState.LocalContentId;
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
var listingsUploadObject = new UniversalisItemListingsUploadRequest
|
||||
{
|
||||
Hq = marketBoardItemListing.IsHq,
|
||||
SellerId = marketBoardItemListing.RetainerOwnerId.ToString(),
|
||||
RetainerName = marketBoardItemListing.RetainerName,
|
||||
RetainerId = marketBoardItemListing.RetainerId.ToString(),
|
||||
CreatorId = marketBoardItemListing.ArtisanId.ToString(),
|
||||
CreatorName = marketBoardItemListing.PlayerName,
|
||||
OnMannequin = marketBoardItemListing.OnMannequin,
|
||||
LastReviewTime = ((DateTimeOffset)marketBoardItemListing.LastReviewTime).ToUnixTimeSeconds(),
|
||||
PricePerUnit = marketBoardItemListing.PricePerUnit,
|
||||
Quantity = marketBoardItemListing.ItemQuantity,
|
||||
RetainerCity = marketBoardItemListing.RetainerCityId,
|
||||
Materia = new List<UniversalisItemMateria>(),
|
||||
WorldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0,
|
||||
UploaderId = uploader.ToString(),
|
||||
ItemId = request.CatalogId,
|
||||
Listings = new List<UniversalisItemListingsEntry>(),
|
||||
};
|
||||
|
||||
foreach (var itemMateria in marketBoardItemListing.Materia)
|
||||
foreach (var marketBoardItemListing in request.Listings)
|
||||
{
|
||||
universalisListing.Materia.Add(new UniversalisItemMateria
|
||||
var universalisListing = new UniversalisItemListingsEntry
|
||||
{
|
||||
MateriaId = itemMateria.MateriaId,
|
||||
SlotId = itemMateria.Index,
|
||||
Hq = marketBoardItemListing.IsHq,
|
||||
SellerId = marketBoardItemListing.RetainerOwnerId.ToString(),
|
||||
RetainerName = marketBoardItemListing.RetainerName,
|
||||
RetainerId = marketBoardItemListing.RetainerId.ToString(),
|
||||
CreatorId = marketBoardItemListing.ArtisanId.ToString(),
|
||||
CreatorName = marketBoardItemListing.PlayerName,
|
||||
OnMannequin = marketBoardItemListing.OnMannequin,
|
||||
LastReviewTime = ((DateTimeOffset)marketBoardItemListing.LastReviewTime).ToUnixTimeSeconds(),
|
||||
PricePerUnit = marketBoardItemListing.PricePerUnit,
|
||||
Quantity = marketBoardItemListing.ItemQuantity,
|
||||
RetainerCity = marketBoardItemListing.RetainerCityId,
|
||||
Materia = new List<UniversalisItemMateria>(),
|
||||
};
|
||||
|
||||
foreach (var itemMateria in marketBoardItemListing.Materia)
|
||||
{
|
||||
universalisListing.Materia.Add(new UniversalisItemMateria
|
||||
{
|
||||
MateriaId = itemMateria.MateriaId,
|
||||
SlotId = itemMateria.Index,
|
||||
});
|
||||
}
|
||||
|
||||
listingsUploadObject.Listings.Add(universalisListing);
|
||||
}
|
||||
|
||||
var listingPath = "/upload";
|
||||
var listingUpload = JsonConvert.SerializeObject(listingsUploadObject);
|
||||
Log.Verbose($"{listingPath}: {listingUpload}");
|
||||
await Util.HttpClient.PostAsync($"{ApiBase}{listingPath}/{ApiKey}", new StringContent(listingUpload, Encoding.UTF8, "application/json"));
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
var historyUploadObject = new UniversalisHistoryUploadRequest
|
||||
{
|
||||
WorldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0,
|
||||
UploaderId = uploader.ToString(),
|
||||
ItemId = request.CatalogId,
|
||||
Entries = new List<UniversalisHistoryEntry>(),
|
||||
};
|
||||
|
||||
foreach (var marketBoardHistoryListing in request.History)
|
||||
{
|
||||
historyUploadObject.Entries.Add(new UniversalisHistoryEntry
|
||||
{
|
||||
BuyerName = marketBoardHistoryListing.BuyerName,
|
||||
Hq = marketBoardHistoryListing.IsHq,
|
||||
OnMannequin = marketBoardHistoryListing.OnMannequin,
|
||||
PricePerUnit = marketBoardHistoryListing.SalePrice,
|
||||
Quantity = marketBoardHistoryListing.Quantity,
|
||||
Timestamp = ((DateTimeOffset)marketBoardHistoryListing.PurchaseTime).ToUnixTimeSeconds(),
|
||||
});
|
||||
}
|
||||
|
||||
listingsUploadObject.Listings.Add(universalisListing);
|
||||
var historyPath = "/upload";
|
||||
var historyUpload = JsonConvert.SerializeObject(historyUploadObject);
|
||||
Log.Verbose($"{historyPath}: {historyUpload}");
|
||||
await Util.HttpClient.PostAsync($"{ApiBase}{historyPath}/{ApiKey}", new StringContent(historyUpload, Encoding.UTF8, "application/json"));
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
Log.Verbose("Universalis data upload for item#{0} completed.", request.CatalogId);
|
||||
}
|
||||
|
||||
var listingPath = "/upload";
|
||||
var listingUpload = JsonConvert.SerializeObject(listingsUploadObject);
|
||||
Log.Verbose($"{listingPath}: {listingUpload}");
|
||||
await Util.HttpClient.PostAsync($"{ApiBase}{listingPath}/{ApiKey}", new StringContent(listingUpload, Encoding.UTF8, "application/json"));
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
var historyUploadObject = new UniversalisHistoryUploadRequest
|
||||
/// <inheritdoc/>
|
||||
public async Task UploadTax(MarketTaxRates taxRates)
|
||||
{
|
||||
WorldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0,
|
||||
UploaderId = uploader.ToString(),
|
||||
ItemId = request.CatalogId,
|
||||
Entries = new List<UniversalisHistoryEntry>(),
|
||||
};
|
||||
var clientState = Service<ClientState.ClientState>.Get();
|
||||
|
||||
foreach (var marketBoardHistoryListing in request.History)
|
||||
{
|
||||
historyUploadObject.Entries.Add(new UniversalisHistoryEntry
|
||||
// ====================================================================================
|
||||
|
||||
var taxUploadObject = new UniversalisTaxUploadRequest
|
||||
{
|
||||
BuyerName = marketBoardHistoryListing.BuyerName,
|
||||
Hq = marketBoardHistoryListing.IsHq,
|
||||
OnMannequin = marketBoardHistoryListing.OnMannequin,
|
||||
PricePerUnit = marketBoardHistoryListing.SalePrice,
|
||||
Quantity = marketBoardHistoryListing.Quantity,
|
||||
Timestamp = ((DateTimeOffset)marketBoardHistoryListing.PurchaseTime).ToUnixTimeSeconds(),
|
||||
});
|
||||
WorldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0,
|
||||
UploaderId = clientState.LocalContentId.ToString(),
|
||||
TaxData = new UniversalisTaxData
|
||||
{
|
||||
LimsaLominsa = taxRates.LimsaLominsaTax,
|
||||
Gridania = taxRates.GridaniaTax,
|
||||
Uldah = taxRates.UldahTax,
|
||||
Ishgard = taxRates.IshgardTax,
|
||||
Kugane = taxRates.KuganeTax,
|
||||
Crystarium = taxRates.CrystariumTax,
|
||||
},
|
||||
};
|
||||
|
||||
var taxPath = "/upload";
|
||||
var taxUpload = JsonConvert.SerializeObject(taxUploadObject);
|
||||
Log.Verbose($"{taxPath}: {taxUpload}");
|
||||
|
||||
await Util.HttpClient.PostAsync($"{ApiBase}{taxPath}/{ApiKey}", new StringContent(taxUpload, Encoding.UTF8, "application/json"));
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
Log.Verbose("Universalis tax upload completed.");
|
||||
}
|
||||
|
||||
var historyPath = "/upload";
|
||||
var historyUpload = JsonConvert.SerializeObject(historyUploadObject);
|
||||
Log.Verbose($"{historyPath}: {historyUpload}");
|
||||
await Util.HttpClient.PostAsync($"{ApiBase}{historyPath}/{ApiKey}", new StringContent(historyUpload, Encoding.UTF8, "application/json"));
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
Log.Verbose("Universalis data upload for item#{0} completed.", request.CatalogId);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task UploadTax(MarketTaxRates taxRates)
|
||||
{
|
||||
var clientState = Service<ClientState.ClientState>.Get();
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
var taxUploadObject = new UniversalisTaxUploadRequest
|
||||
/// <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 async Task UploadPurchase(MarketBoardPurchaseHandler purchaseHandler)
|
||||
{
|
||||
WorldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0,
|
||||
UploaderId = clientState.LocalContentId.ToString(),
|
||||
TaxData = new UniversalisTaxData
|
||||
var clientState = Service<ClientState.ClientState>.Get();
|
||||
|
||||
var itemId = purchaseHandler.CatalogId;
|
||||
var worldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0;
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
var deleteListingObject = new UniversalisItemListingDeleteRequest
|
||||
{
|
||||
LimsaLominsa = taxRates.LimsaLominsaTax,
|
||||
Gridania = taxRates.GridaniaTax,
|
||||
Uldah = taxRates.UldahTax,
|
||||
Ishgard = taxRates.IshgardTax,
|
||||
Kugane = taxRates.KuganeTax,
|
||||
Crystarium = taxRates.CrystariumTax,
|
||||
},
|
||||
};
|
||||
PricePerUnit = purchaseHandler.PricePerUnit,
|
||||
Quantity = purchaseHandler.ItemQuantity,
|
||||
ListingId = purchaseHandler.ListingId.ToString(),
|
||||
RetainerId = purchaseHandler.RetainerId.ToString(),
|
||||
UploaderId = clientState.LocalContentId.ToString(),
|
||||
};
|
||||
|
||||
var taxPath = "/upload";
|
||||
var taxUpload = JsonConvert.SerializeObject(taxUploadObject);
|
||||
Log.Verbose($"{taxPath}: {taxUpload}");
|
||||
var deletePath = $"/api/{worldId}/{itemId}/delete";
|
||||
var deleteListing = JsonConvert.SerializeObject(deleteListingObject);
|
||||
Log.Verbose($"{deletePath}: {deleteListing}");
|
||||
|
||||
await Util.HttpClient.PostAsync($"{ApiBase}{taxPath}/{ApiKey}", new StringContent(taxUpload, Encoding.UTF8, "application/json"));
|
||||
var content = new StringContent(deleteListing, Encoding.UTF8, "application/json");
|
||||
var message = new HttpRequestMessage(HttpMethod.Post, $"{ApiBase}{deletePath}");
|
||||
message.Headers.Add("Authorization", ApiKey);
|
||||
message.Content = content;
|
||||
|
||||
// ====================================================================================
|
||||
await Util.HttpClient.SendAsync(message);
|
||||
|
||||
Log.Verbose("Universalis tax upload completed.");
|
||||
}
|
||||
// ====================================================================================
|
||||
|
||||
/// <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 async Task UploadPurchase(MarketBoardPurchaseHandler purchaseHandler)
|
||||
{
|
||||
var clientState = Service<ClientState.ClientState>.Get();
|
||||
|
||||
var itemId = purchaseHandler.CatalogId;
|
||||
var worldId = clientState.LocalPlayer?.CurrentWorld.Id ?? 0;
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
var deleteListingObject = new UniversalisItemListingDeleteRequest
|
||||
{
|
||||
PricePerUnit = purchaseHandler.PricePerUnit,
|
||||
Quantity = purchaseHandler.ItemQuantity,
|
||||
ListingId = purchaseHandler.ListingId.ToString(),
|
||||
RetainerId = purchaseHandler.RetainerId.ToString(),
|
||||
UploaderId = clientState.LocalContentId.ToString(),
|
||||
};
|
||||
|
||||
var deletePath = $"/api/{worldId}/{itemId}/delete";
|
||||
var deleteListing = JsonConvert.SerializeObject(deleteListingObject);
|
||||
Log.Verbose($"{deletePath}: {deleteListing}");
|
||||
|
||||
var content = new StringContent(deleteListing, Encoding.UTF8, "application/json");
|
||||
var message = new HttpRequestMessage(HttpMethod.Post, $"{ApiBase}{deletePath}");
|
||||
message.Headers.Add("Authorization", ApiKey);
|
||||
message.Content = content;
|
||||
|
||||
await Util.HttpClient.SendAsync(message);
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
Log.Verbose("Universalis purchase upload completed.");
|
||||
Log.Verbose("Universalis purchase upload completed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,277 +16,278 @@ using Dalamud.Utility;
|
|||
using Lumina.Excel.GeneratedSheets;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// This class handles network notifications and uploading market board data.
|
||||
/// </summary>
|
||||
internal class NetworkHandlers
|
||||
namespace Dalamud.Game.Network.Internal
|
||||
{
|
||||
private readonly List<MarketBoardItemRequest> marketBoardRequests = new();
|
||||
|
||||
private readonly bool optOutMbUploads;
|
||||
private readonly IMarketBoardUploader uploader;
|
||||
|
||||
private MarketBoardPurchaseHandler marketBoardPurchaseHandler;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NetworkHandlers"/> class.
|
||||
/// This class handles network notifications and uploading market board data.
|
||||
/// </summary>
|
||||
public NetworkHandlers()
|
||||
internal class NetworkHandlers
|
||||
{
|
||||
this.optOutMbUploads = Service<DalamudStartInfo>.Get().OptOutMbCollection;
|
||||
private readonly List<MarketBoardItemRequest> marketBoardRequests = new();
|
||||
|
||||
this.uploader = new UniversalisMarketBoardUploader();
|
||||
private readonly bool optOutMbUploads;
|
||||
private readonly IMarketBoardUploader uploader;
|
||||
|
||||
Service<GameNetwork>.Get().NetworkMessage += this.OnNetworkMessage;
|
||||
}
|
||||
private MarketBoardPurchaseHandler marketBoardPurchaseHandler;
|
||||
|
||||
/// <summary>
|
||||
/// Event which gets fired when a duty is ready.
|
||||
/// </summary>
|
||||
public event EventHandler<ContentFinderCondition> CfPop;
|
||||
|
||||
private void OnNetworkMessage(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction)
|
||||
{
|
||||
var dataManager = Service<DataManager>.GetNullable();
|
||||
|
||||
if (dataManager?.IsDataReady == false)
|
||||
return;
|
||||
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
if (direction == NetworkMessageDirection.ZoneUp)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NetworkHandlers"/> class.
|
||||
/// </summary>
|
||||
public NetworkHandlers()
|
||||
{
|
||||
this.optOutMbUploads = Service<DalamudStartInfo>.Get().OptOutMbCollection;
|
||||
|
||||
this.uploader = new UniversalisMarketBoardUploader();
|
||||
|
||||
Service<GameNetwork>.Get().NetworkMessage += this.OnNetworkMessage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event which gets fired when a duty is ready.
|
||||
/// </summary>
|
||||
public event EventHandler<ContentFinderCondition> CfPop;
|
||||
|
||||
private void OnNetworkMessage(IntPtr dataPtr, ushort opCode, uint sourceActorId, uint targetActorId, NetworkMessageDirection direction)
|
||||
{
|
||||
var dataManager = Service<DataManager>.GetNullable();
|
||||
|
||||
if (dataManager?.IsDataReady == false)
|
||||
return;
|
||||
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
if (direction == NetworkMessageDirection.ZoneUp)
|
||||
{
|
||||
if (!this.optOutMbUploads)
|
||||
{
|
||||
if (opCode == dataManager.ClientOpCodes["MarketBoardPurchaseHandler"])
|
||||
{
|
||||
this.marketBoardPurchaseHandler = MarketBoardPurchaseHandler.Read(dataPtr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (opCode == dataManager.ServerOpCodes["CfNotifyPop"])
|
||||
{
|
||||
this.HandleCfPop(dataPtr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.optOutMbUploads)
|
||||
{
|
||||
if (opCode == dataManager.ClientOpCodes["MarketBoardPurchaseHandler"])
|
||||
if (opCode == dataManager.ServerOpCodes["MarketBoardItemRequestStart"])
|
||||
{
|
||||
this.marketBoardPurchaseHandler = MarketBoardPurchaseHandler.Read(dataPtr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
var data = MarketBoardItemRequest.Read(dataPtr);
|
||||
this.marketBoardRequests.Add(data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (opCode == dataManager.ServerOpCodes["CfNotifyPop"])
|
||||
{
|
||||
this.HandleCfPop(dataPtr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.optOutMbUploads)
|
||||
{
|
||||
if (opCode == dataManager.ServerOpCodes["MarketBoardItemRequestStart"])
|
||||
{
|
||||
var data = MarketBoardItemRequest.Read(dataPtr);
|
||||
this.marketBoardRequests.Add(data);
|
||||
|
||||
Log.Verbose($"NEW MB REQUEST START: item#{data.CatalogId} amount#{data.AmountToArrive}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (opCode == dataManager.ServerOpCodes["MarketBoardOfferings"])
|
||||
{
|
||||
var listing = MarketBoardCurrentOfferings.Read(dataPtr);
|
||||
|
||||
var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone);
|
||||
|
||||
if (request == default)
|
||||
{
|
||||
Log.Error($"Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}");
|
||||
Log.Verbose($"NEW MB REQUEST START: item#{data.CatalogId} amount#{data.AmountToArrive}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.Listings.Count + listing.ItemListings.Count > request.AmountToArrive)
|
||||
if (opCode == dataManager.ServerOpCodes["MarketBoardOfferings"])
|
||||
{
|
||||
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 listing = MarketBoardCurrentOfferings.Read(dataPtr);
|
||||
|
||||
if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId)
|
||||
{
|
||||
Log.Error($"Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}");
|
||||
return;
|
||||
}
|
||||
var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.ItemListings[0].CatalogId && !r.IsDone);
|
||||
|
||||
if (request.ListingsRequestId == -1 && request.Listings.Count > 0)
|
||||
{
|
||||
Log.Error($"Market Board data request sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
|
||||
return;
|
||||
}
|
||||
if (request == default)
|
||||
{
|
||||
Log.Error($"Market Board data arrived without a corresponding request: item#{listing.ItemListings[0].CatalogId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.ListingsRequestId == -1)
|
||||
{
|
||||
request.ListingsRequestId = listing.RequestId;
|
||||
Log.Verbose($"First Market Board packet in sequence: {listing.RequestId}");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
request.Listings.AddRange(listing.ItemListings);
|
||||
if (request.ListingsRequestId != -1 && request.ListingsRequestId != listing.RequestId)
|
||||
{
|
||||
Log.Error($"Non-matching RequestIds for Market Board data request: {request.ListingsRequestId}, {listing.RequestId}");
|
||||
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);
|
||||
if (request.ListingsRequestId == -1 && request.Listings.Count > 0)
|
||||
{
|
||||
Log.Error($"Market Board data request 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.Listings.AddRange(listing.ItemListings);
|
||||
|
||||
if (request.IsDone)
|
||||
{
|
||||
Log.Verbose(
|
||||
"Market Board request finished, starting upload: request#{0} item#{1} amount#{2}",
|
||||
"Added {0} ItemListings to request#{1}, now {2}/{3}, item#{4}",
|
||||
listing.ItemListings.Count,
|
||||
request.ListingsRequestId,
|
||||
request.CatalogId,
|
||||
request.AmountToArrive);
|
||||
request.Listings.Count,
|
||||
request.AmountToArrive,
|
||||
request.CatalogId);
|
||||
|
||||
Task.Run(() => this.uploader.Upload(request))
|
||||
.ContinueWith((task) => Log.Error(task.Exception, "Market Board offerings data upload failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
if (request.IsDone)
|
||||
{
|
||||
Log.Verbose(
|
||||
"Market Board request finished, starting upload: request#{0} item#{1} amount#{2}",
|
||||
request.ListingsRequestId,
|
||||
request.CatalogId,
|
||||
request.AmountToArrive);
|
||||
|
||||
Task.Run(() => this.uploader.Upload(request))
|
||||
.ContinueWith((task) => Log.Error(task.Exception, "Market Board offerings data upload failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (opCode == dataManager.ServerOpCodes["MarketBoardHistory"])
|
||||
{
|
||||
var listing = MarketBoardHistory.Read(dataPtr);
|
||||
|
||||
var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId);
|
||||
|
||||
if (request == default)
|
||||
{
|
||||
Log.Error($"Market Board data arrived without a corresponding request: item#{listing.CatalogId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.ListingsRequestId != -1)
|
||||
{
|
||||
Log.Error($"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
|
||||
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");
|
||||
|
||||
Task.Run(() => this.uploader.Upload(request))
|
||||
.ContinueWith((task) => Log.Error(task.Exception, "Market Board history data upload failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
}
|
||||
|
||||
if (opCode == dataManager.ServerOpCodes["MarketTaxRates"])
|
||||
{
|
||||
var category = (uint)Marshal.ReadInt32(dataPtr);
|
||||
|
||||
// Result dialog packet does not contain market tax rates
|
||||
if (category != 720905)
|
||||
{
|
||||
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);
|
||||
|
||||
Task.Run(() => this.uploader.UploadTax(taxes))
|
||||
.ContinueWith((task) => Log.Error(task.Exception, "Market Board tax data upload failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (opCode == dataManager.ServerOpCodes["MarketBoardPurchase"])
|
||||
{
|
||||
if (this.marketBoardPurchaseHandler == null)
|
||||
return;
|
||||
|
||||
var purchase = MarketBoardPurchase.Read(dataPtr);
|
||||
|
||||
var sameQty = purchase.ItemQuantity == this.marketBoardPurchaseHandler.ItemQuantity;
|
||||
var itemMatch = purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId;
|
||||
var itemMatchHq = purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId + 1_000_000;
|
||||
|
||||
// Transaction succeeded
|
||||
if (sameQty && (itemMatch || itemMatchHq))
|
||||
{
|
||||
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.
|
||||
|
||||
Task.Run(() => this.uploader.UploadPurchase(handler))
|
||||
.ContinueWith((task) => Log.Error(task.Exception, "Market Board purchase data upload failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
|
||||
this.marketBoardPurchaseHandler = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void HandleCfPop(IntPtr dataPtr)
|
||||
{
|
||||
var dataManager = Service<DataManager>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 64);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
var notifyType = reader.ReadByte();
|
||||
stream.Position += 0x13;
|
||||
var conditionId = reader.ReadUInt16();
|
||||
|
||||
if (notifyType != 3)
|
||||
return;
|
||||
|
||||
var cfConditionSheet = dataManager.GetExcelSheet<ContentFinderCondition>()!;
|
||||
var cfCondition = cfConditionSheet.GetRow(conditionId);
|
||||
|
||||
if (cfCondition == null)
|
||||
{
|
||||
Log.Error($"CFC key {conditionId} not in Lumina data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (opCode == dataManager.ServerOpCodes["MarketBoardHistory"])
|
||||
var cfcName = cfCondition.Name.ToString();
|
||||
if (cfcName.IsNullOrEmpty())
|
||||
{
|
||||
var listing = MarketBoardHistory.Read(dataPtr);
|
||||
|
||||
var request = this.marketBoardRequests.LastOrDefault(r => r.CatalogId == listing.CatalogId);
|
||||
|
||||
if (request == default)
|
||||
{
|
||||
Log.Error($"Market Board data arrived without a corresponding request: item#{listing.CatalogId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.ListingsRequestId != -1)
|
||||
{
|
||||
Log.Error($"Market Board data history sequence break: {request.ListingsRequestId}, {request.Listings.Count}");
|
||||
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");
|
||||
|
||||
Task.Run(() => this.uploader.Upload(request))
|
||||
.ContinueWith((task) => Log.Error(task.Exception, "Market Board history data upload failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
cfcName = "Duty Roulette";
|
||||
cfCondition.Image = 112324;
|
||||
}
|
||||
|
||||
if (opCode == dataManager.ServerOpCodes["MarketTaxRates"])
|
||||
// Flash window
|
||||
if (configuration.DutyFinderTaskbarFlash && !NativeFunctions.ApplicationIsActivated())
|
||||
{
|
||||
var category = (uint)Marshal.ReadInt32(dataPtr);
|
||||
|
||||
// Result dialog packet does not contain market tax rates
|
||||
if (category != 720905)
|
||||
var flashInfo = new NativeFunctions.FlashWindowInfo
|
||||
{
|
||||
return;
|
||||
Size = (uint)Marshal.SizeOf<NativeFunctions.FlashWindowInfo>(),
|
||||
Count = uint.MaxValue,
|
||||
Timeout = 0,
|
||||
Flags = NativeFunctions.FlashWindow.All | NativeFunctions.FlashWindow.TimerNoFG,
|
||||
Hwnd = Process.GetCurrentProcess().MainWindowHandle,
|
||||
};
|
||||
NativeFunctions.FlashWindowEx(ref flashInfo);
|
||||
}
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (configuration.DutyFinderChatMessage)
|
||||
{
|
||||
Service<ChatGui>.Get().Print($"Duty pop: {cfcName}");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Task.Run(() => this.uploader.UploadTax(taxes))
|
||||
.ContinueWith((task) => Log.Error(task.Exception, "Market Board tax data upload failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (opCode == dataManager.ServerOpCodes["MarketBoardPurchase"])
|
||||
{
|
||||
if (this.marketBoardPurchaseHandler == null)
|
||||
return;
|
||||
|
||||
var purchase = MarketBoardPurchase.Read(dataPtr);
|
||||
|
||||
var sameQty = purchase.ItemQuantity == this.marketBoardPurchaseHandler.ItemQuantity;
|
||||
var itemMatch = purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId;
|
||||
var itemMatchHq = purchase.CatalogId == this.marketBoardPurchaseHandler.CatalogId + 1_000_000;
|
||||
|
||||
// Transaction succeeded
|
||||
if (sameQty && (itemMatch || itemMatchHq))
|
||||
{
|
||||
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.
|
||||
|
||||
Task.Run(() => this.uploader.UploadPurchase(handler))
|
||||
.ContinueWith((task) => Log.Error(task.Exception, "Market Board purchase data upload failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
|
||||
this.marketBoardPurchaseHandler = null;
|
||||
return;
|
||||
}
|
||||
this.CfPop?.Invoke(this, cfCondition);
|
||||
}).ContinueWith((task) => Log.Error(task.Exception, "CfPop.Invoke failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void HandleCfPop(IntPtr dataPtr)
|
||||
{
|
||||
var dataManager = Service<DataManager>.Get();
|
||||
var configuration = Service<DalamudConfiguration>.Get();
|
||||
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 64);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
var notifyType = reader.ReadByte();
|
||||
stream.Position += 0x13;
|
||||
var conditionId = reader.ReadUInt16();
|
||||
|
||||
if (notifyType != 3)
|
||||
return;
|
||||
|
||||
var cfConditionSheet = dataManager.GetExcelSheet<ContentFinderCondition>()!;
|
||||
var cfCondition = cfConditionSheet.GetRow(conditionId);
|
||||
|
||||
if (cfCondition == null)
|
||||
{
|
||||
Log.Error($"CFC key {conditionId} not in Lumina data.");
|
||||
return;
|
||||
}
|
||||
|
||||
var cfcName = cfCondition.Name.ToString();
|
||||
if (cfcName.IsNullOrEmpty())
|
||||
{
|
||||
cfcName = "Duty Roulette";
|
||||
cfCondition.Image = 112324;
|
||||
}
|
||||
|
||||
// Flash window
|
||||
if (configuration.DutyFinderTaskbarFlash && !NativeFunctions.ApplicationIsActivated())
|
||||
{
|
||||
var flashInfo = new NativeFunctions.FlashWindowInfo
|
||||
{
|
||||
Size = (uint)Marshal.SizeOf<NativeFunctions.FlashWindowInfo>(),
|
||||
Count = uint.MaxValue,
|
||||
Timeout = 0,
|
||||
Flags = NativeFunctions.FlashWindow.All | NativeFunctions.FlashWindow.TimerNoFG,
|
||||
Hwnd = Process.GetCurrentProcess().MainWindowHandle,
|
||||
};
|
||||
NativeFunctions.FlashWindowEx(ref flashInfo);
|
||||
}
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (configuration.DutyFinderChatMessage)
|
||||
{
|
||||
Service<ChatGui>.Get().Print($"Duty pop: {cfcName}");
|
||||
}
|
||||
|
||||
this.CfPop?.Invoke(this, cfCondition);
|
||||
}).ContinueWith((task) => Log.Error(task.Exception, "CfPop.Invoke failed."), TaskContinuationOptions.OnlyOnFaulted);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,57 +5,58 @@ using System.Runtime.InteropServices;
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.Hooking.Internal;
|
||||
|
||||
namespace Dalamud.Game.Network.Internal;
|
||||
|
||||
/// <summary>
|
||||
/// This class enables TCP optimizations in the game socket for better performance.
|
||||
/// </summary>
|
||||
internal sealed class WinSockHandlers : IDisposable
|
||||
namespace Dalamud.Game.Network.Internal
|
||||
{
|
||||
private Hook<SocketDelegate> ws2SocketHook;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WinSockHandlers"/> class.
|
||||
/// This class enables TCP optimizations in the game socket for better performance.
|
||||
/// </summary>
|
||||
public WinSockHandlers()
|
||||
internal sealed class WinSockHandlers : IDisposable
|
||||
{
|
||||
this.ws2SocketHook = Hook<SocketDelegate>.FromSymbol("ws2_32.dll", "socket", this.OnSocket, true);
|
||||
this.ws2SocketHook?.Enable();
|
||||
}
|
||||
private Hook<SocketDelegate> ws2SocketHook;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
private delegate IntPtr SocketDelegate(int af, int type, int protocol);
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.ws2SocketHook?.Dispose();
|
||||
}
|
||||
|
||||
private IntPtr OnSocket(int af, int type, int protocol)
|
||||
{
|
||||
var socket = this.ws2SocketHook.Original(af, type, protocol);
|
||||
|
||||
// IPPROTO_TCP
|
||||
if (type == 1)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WinSockHandlers"/> class.
|
||||
/// </summary>
|
||||
public WinSockHandlers()
|
||||
{
|
||||
// INVALID_SOCKET
|
||||
if (socket != new IntPtr(-1))
|
||||
{
|
||||
// In case you're not aware of it: (albeit you should)
|
||||
// https://linux.die.net/man/7/tcp
|
||||
// https://assets.extrahop.com/whitepapers/TCP-Optimization-Guide-by-ExtraHop.pdf
|
||||
var value = new IntPtr(1);
|
||||
_ = NativeFunctions.SetSockOpt(socket, SocketOptionLevel.Tcp, SocketOptionName.NoDelay, ref value, 4);
|
||||
|
||||
// Enable tcp_quickack option. This option is undocumented in MSDN but it is supported in Windows 7 and onwards.
|
||||
value = new IntPtr(1);
|
||||
_ = NativeFunctions.SetSockOpt(socket, SocketOptionLevel.Tcp, SocketOptionName.AddMembership, ref value, 4);
|
||||
}
|
||||
this.ws2SocketHook = Hook<SocketDelegate>.FromSymbol("ws2_32.dll", "socket", this.OnSocket, true);
|
||||
this.ws2SocketHook?.Enable();
|
||||
}
|
||||
|
||||
return socket;
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
private delegate IntPtr SocketDelegate(int af, int type, int protocol);
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.ws2SocketHook?.Dispose();
|
||||
}
|
||||
|
||||
private IntPtr OnSocket(int af, int type, int protocol)
|
||||
{
|
||||
var socket = this.ws2SocketHook.Original(af, type, protocol);
|
||||
|
||||
// IPPROTO_TCP
|
||||
if (type == 1)
|
||||
{
|
||||
// INVALID_SOCKET
|
||||
if (socket != new IntPtr(-1))
|
||||
{
|
||||
// In case you're not aware of it: (albeit you should)
|
||||
// https://linux.die.net/man/7/tcp
|
||||
// https://assets.extrahop.com/whitepapers/TCP-Optimization-Guide-by-ExtraHop.pdf
|
||||
var value = new IntPtr(1);
|
||||
_ = NativeFunctions.SetSockOpt(socket, SocketOptionLevel.Tcp, SocketOptionName.NoDelay, ref value, 4);
|
||||
|
||||
// Enable tcp_quickack option. This option is undocumented in MSDN but it is supported in Windows 7 and onwards.
|
||||
value = new IntPtr(1);
|
||||
_ = NativeFunctions.SetSockOpt(socket, SocketOptionLevel.Tcp, SocketOptionName.AddMembership, ref value, 4);
|
||||
}
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
namespace Dalamud.Game.Network;
|
||||
|
||||
/// <summary>
|
||||
/// This represents the direction of a network message.
|
||||
/// </summary>
|
||||
public enum NetworkMessageDirection
|
||||
namespace Dalamud.Game.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// A zone down message.
|
||||
/// This represents the direction of a network message.
|
||||
/// </summary>
|
||||
ZoneDown,
|
||||
public enum NetworkMessageDirection
|
||||
{
|
||||
/// <summary>
|
||||
/// A zone down message.
|
||||
/// </summary>
|
||||
ZoneDown,
|
||||
|
||||
/// <summary>
|
||||
/// A zone up message.
|
||||
/// </summary>
|
||||
ZoneUp,
|
||||
/// <summary>
|
||||
/// A zone up message.
|
||||
/// </summary>
|
||||
ZoneUp,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,224 +3,225 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Dalamud.Game.Network.Structures;
|
||||
|
||||
/// <summary>
|
||||
/// This class represents the current market board offerings from a game network packet.
|
||||
/// </summary>
|
||||
public class MarketBoardCurrentOfferings
|
||||
namespace Dalamud.Game.Network.Structures
|
||||
{
|
||||
private MarketBoardCurrentOfferings()
|
||||
/// <summary>
|
||||
/// This class represents the current market board offerings from a game network packet.
|
||||
/// </summary>
|
||||
public class MarketBoardCurrentOfferings
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of individual item listings.
|
||||
/// </summary>
|
||||
public List<MarketBoardItemListing> ItemListings { get; } = new();
|
||||
|
||||
/// <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)
|
||||
{
|
||||
var output = new MarketBoardCurrentOfferings();
|
||||
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
private MarketBoardCurrentOfferings()
|
||||
{
|
||||
var listingEntry = new MarketBoardItemListing();
|
||||
}
|
||||
|
||||
listingEntry.ListingId = reader.ReadUInt64();
|
||||
listingEntry.RetainerId = reader.ReadUInt64();
|
||||
listingEntry.RetainerOwnerId = reader.ReadUInt64();
|
||||
listingEntry.ArtisanId = reader.ReadUInt64();
|
||||
listingEntry.PricePerUnit = reader.ReadUInt32();
|
||||
listingEntry.TotalTax = reader.ReadUInt32();
|
||||
listingEntry.ItemQuantity = reader.ReadUInt32();
|
||||
listingEntry.CatalogId = reader.ReadUInt32();
|
||||
listingEntry.LastReviewTime = DateTimeOffset.UtcNow.AddSeconds(-reader.ReadUInt16()).DateTime;
|
||||
/// <summary>
|
||||
/// Gets the list of individual item listings.
|
||||
/// </summary>
|
||||
public List<MarketBoardItemListing> ItemListings { get; } = new();
|
||||
|
||||
reader.ReadUInt16(); // container
|
||||
reader.ReadUInt32(); // slot
|
||||
reader.ReadUInt16(); // durability
|
||||
reader.ReadUInt16(); // spiritbond
|
||||
/// <summary>
|
||||
/// Gets the listing end index.
|
||||
/// </summary>
|
||||
public int ListingIndexEnd { get; internal set; }
|
||||
|
||||
for (var materiaIndex = 0; materiaIndex < 5; materiaIndex++)
|
||||
/// <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)
|
||||
{
|
||||
var output = new MarketBoardCurrentOfferings();
|
||||
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var materiaVal = reader.ReadUInt16();
|
||||
var materiaEntry = new MarketBoardItemListing.ItemMateria()
|
||||
var listingEntry = new MarketBoardItemListing();
|
||||
|
||||
listingEntry.ListingId = reader.ReadUInt64();
|
||||
listingEntry.RetainerId = reader.ReadUInt64();
|
||||
listingEntry.RetainerOwnerId = reader.ReadUInt64();
|
||||
listingEntry.ArtisanId = reader.ReadUInt64();
|
||||
listingEntry.PricePerUnit = reader.ReadUInt32();
|
||||
listingEntry.TotalTax = reader.ReadUInt32();
|
||||
listingEntry.ItemQuantity = reader.ReadUInt32();
|
||||
listingEntry.CatalogId = reader.ReadUInt32();
|
||||
listingEntry.LastReviewTime = DateTimeOffset.UtcNow.AddSeconds(-reader.ReadUInt16()).DateTime;
|
||||
|
||||
reader.ReadUInt16(); // container
|
||||
reader.ReadUInt32(); // slot
|
||||
reader.ReadUInt16(); // durability
|
||||
reader.ReadUInt16(); // spiritbond
|
||||
|
||||
for (var materiaIndex = 0; materiaIndex < 5; materiaIndex++)
|
||||
{
|
||||
MateriaId = (materiaVal & 0xFF0) >> 4,
|
||||
Index = materiaVal & 0xF,
|
||||
};
|
||||
var materiaVal = reader.ReadUInt16();
|
||||
var materiaEntry = new MarketBoardItemListing.ItemMateria()
|
||||
{
|
||||
MateriaId = (materiaVal & 0xFF0) >> 4,
|
||||
Index = materiaVal & 0xF,
|
||||
};
|
||||
|
||||
if (materiaEntry.MateriaId != 0)
|
||||
listingEntry.Materia.Add(materiaEntry);
|
||||
if (materiaEntry.MateriaId != 0)
|
||||
listingEntry.Materia.Add(materiaEntry);
|
||||
}
|
||||
|
||||
reader.ReadUInt16();
|
||||
reader.ReadUInt32();
|
||||
|
||||
listingEntry.RetainerName = Encoding.UTF8.GetString(reader.ReadBytes(32)).TrimEnd('\u0000');
|
||||
listingEntry.PlayerName = Encoding.UTF8.GetString(reader.ReadBytes(32)).TrimEnd('\u0000');
|
||||
listingEntry.IsHq = reader.ReadBoolean();
|
||||
listingEntry.MateriaCount = reader.ReadByte();
|
||||
listingEntry.OnMannequin = reader.ReadBoolean();
|
||||
listingEntry.RetainerCityId = reader.ReadByte();
|
||||
listingEntry.StainId = reader.ReadUInt16();
|
||||
|
||||
reader.ReadUInt16();
|
||||
reader.ReadUInt32();
|
||||
|
||||
if (listingEntry.CatalogId != 0)
|
||||
output.ItemListings.Add(listingEntry);
|
||||
}
|
||||
|
||||
reader.ReadUInt16();
|
||||
reader.ReadUInt32();
|
||||
output.ListingIndexEnd = reader.ReadByte();
|
||||
output.ListingIndexStart = reader.ReadByte();
|
||||
output.RequestId = reader.ReadUInt16();
|
||||
|
||||
listingEntry.RetainerName = Encoding.UTF8.GetString(reader.ReadBytes(32)).TrimEnd('\u0000');
|
||||
listingEntry.PlayerName = Encoding.UTF8.GetString(reader.ReadBytes(32)).TrimEnd('\u0000');
|
||||
listingEntry.IsHq = reader.ReadBoolean();
|
||||
listingEntry.MateriaCount = reader.ReadByte();
|
||||
listingEntry.OnMannequin = reader.ReadBoolean();
|
||||
listingEntry.RetainerCityId = reader.ReadByte();
|
||||
listingEntry.StainId = reader.ReadUInt16();
|
||||
|
||||
reader.ReadUInt16();
|
||||
reader.ReadUInt32();
|
||||
|
||||
if (listingEntry.CatalogId != 0)
|
||||
output.ItemListings.Add(listingEntry);
|
||||
}
|
||||
|
||||
output.ListingIndexEnd = reader.ReadByte();
|
||||
output.ListingIndexStart = reader.ReadByte();
|
||||
output.RequestId = reader.ReadUInt16();
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarketBoardItemListing"/> class.
|
||||
/// </summary>
|
||||
internal MarketBoardItemListing()
|
||||
{
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the artisan ID.
|
||||
/// This class represents the current market board offering of a single item from the <see cref="MarketBoardCurrentOfferings"/> network packet.
|
||||
/// </summary>
|
||||
public ulong ArtisanId { get; internal set; }
|
||||
|
||||
/// <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 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; } = new();
|
||||
|
||||
/// <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 MarketBoardItemListing
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ItemMateria"/> class.
|
||||
/// Initializes a new instance of the <see cref="MarketBoardItemListing"/> class.
|
||||
/// </summary>
|
||||
internal ItemMateria()
|
||||
internal MarketBoardItemListing()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the materia index.
|
||||
/// Gets the artisan ID.
|
||||
/// </summary>
|
||||
public int Index { get; internal set; }
|
||||
public ulong ArtisanId { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the materia ID.
|
||||
/// Gets the catalog ID.
|
||||
/// </summary>
|
||||
public int MateriaId { get; internal set; }
|
||||
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; } = new();
|
||||
|
||||
/// <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
|
||||
{
|
||||
/// <summary>
|
||||
/// 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,120 +3,121 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Dalamud.Game.Network.Structures;
|
||||
|
||||
/// <summary>
|
||||
/// This class represents the market board history from a game network packet.
|
||||
/// </summary>
|
||||
public class MarketBoardHistory
|
||||
namespace Dalamud.Game.Network.Structures
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarketBoardHistory"/> class.
|
||||
/// This class represents the market board history from a game network packet.
|
||||
/// </summary>
|
||||
internal MarketBoardHistory()
|
||||
public class MarketBoardHistory
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the catalog ID.
|
||||
/// </summary>
|
||||
public uint CatalogId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the second catalog ID.
|
||||
/// </summary>
|
||||
public uint CatalogId2 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of individual item history listings.
|
||||
/// </summary>
|
||||
public List<MarketBoardHistoryListing> HistoryListings { get; } = new();
|
||||
|
||||
/// <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)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
var output = new MarketBoardHistory();
|
||||
|
||||
output.CatalogId = reader.ReadUInt32();
|
||||
output.CatalogId2 = reader.ReadUInt32();
|
||||
|
||||
for (var i = 0; i < 20; i++)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarketBoardHistory"/> class.
|
||||
/// </summary>
|
||||
internal MarketBoardHistory()
|
||||
{
|
||||
var listingEntry = new MarketBoardHistoryListing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the catalog ID.
|
||||
/// </summary>
|
||||
public uint CatalogId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the second catalog ID.
|
||||
/// </summary>
|
||||
public uint CatalogId2 { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of individual item history listings.
|
||||
/// </summary>
|
||||
public List<MarketBoardHistoryListing> HistoryListings { get; } = new();
|
||||
|
||||
/// <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)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
var output = new MarketBoardHistory();
|
||||
|
||||
output.CatalogId = reader.ReadUInt32();
|
||||
output.CatalogId2 = reader.ReadUInt32();
|
||||
|
||||
for (var i = 0; i < 20; i++)
|
||||
{
|
||||
SalePrice = reader.ReadUInt32(),
|
||||
PurchaseTime = DateTimeOffset.FromUnixTimeSeconds(reader.ReadUInt32()).UtcDateTime,
|
||||
Quantity = reader.ReadUInt32(),
|
||||
IsHq = reader.ReadBoolean(),
|
||||
};
|
||||
var listingEntry = new MarketBoardHistoryListing
|
||||
{
|
||||
SalePrice = reader.ReadUInt32(),
|
||||
PurchaseTime = DateTimeOffset.FromUnixTimeSeconds(reader.ReadUInt32()).UtcDateTime,
|
||||
Quantity = reader.ReadUInt32(),
|
||||
IsHq = reader.ReadBoolean(),
|
||||
};
|
||||
|
||||
reader.ReadBoolean();
|
||||
reader.ReadBoolean();
|
||||
|
||||
listingEntry.OnMannequin = reader.ReadBoolean();
|
||||
listingEntry.BuyerName = Encoding.UTF8.GetString(reader.ReadBytes(33)).TrimEnd('\u0000');
|
||||
listingEntry.NextCatalogId = reader.ReadUInt32();
|
||||
listingEntry.OnMannequin = reader.ReadBoolean();
|
||||
listingEntry.BuyerName = Encoding.UTF8.GetString(reader.ReadBytes(33)).TrimEnd('\u0000');
|
||||
listingEntry.NextCatalogId = reader.ReadUInt32();
|
||||
|
||||
output.HistoryListings.Add(listingEntry);
|
||||
output.HistoryListings.Add(listingEntry);
|
||||
|
||||
if (listingEntry.NextCatalogId == 0)
|
||||
break;
|
||||
if (listingEntry.NextCatalogId == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarketBoardHistoryListing"/> class.
|
||||
/// This class represents the market board history of a single item from the <see cref="MarketBoardHistory"/> network packet.
|
||||
/// </summary>
|
||||
internal MarketBoardHistoryListing()
|
||||
public class MarketBoardHistoryListing
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarketBoardHistoryListing"/> class.
|
||||
/// </summary>
|
||||
internal MarketBoardHistoryListing()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buyer's name.
|
||||
/// </summary>
|
||||
public string BuyerName { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next entry's catalog ID.
|
||||
/// </summary>
|
||||
public uint NextCatalogId { 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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buyer's name.
|
||||
/// </summary>
|
||||
public string BuyerName { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next entry's catalog ID.
|
||||
/// </summary>
|
||||
public uint NextCatalogId { 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; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +1,45 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Dalamud.Game.Network.Structures;
|
||||
|
||||
/// <summary>
|
||||
/// Represents market board purchase information. This message is received from the
|
||||
/// server when a purchase is made at a market board.
|
||||
/// </summary>
|
||||
internal class MarketBoardPurchase
|
||||
namespace Dalamud.Game.Network.Structures
|
||||
{
|
||||
private MarketBoardPurchase()
|
||||
/// <summary>
|
||||
/// Represents market board purchase information. This message is received from the
|
||||
/// server when a purchase is made at a market board.
|
||||
/// </summary>
|
||||
internal class MarketBoardPurchase
|
||||
{
|
||||
}
|
||||
private MarketBoardPurchase()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item ID of the item that was purchased.
|
||||
/// </summary>
|
||||
public uint CatalogId { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the item ID of the item that was purchased.
|
||||
/// </summary>
|
||||
public uint CatalogId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quantity of the item that was purchased.
|
||||
/// </summary>
|
||||
public uint ItemQuantity { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the quantity of the item that was purchased.
|
||||
/// </summary>
|
||||
public uint ItemQuantity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reads market board purchase information from the struct at the provided pointer.
|
||||
/// </summary>
|
||||
/// <param name="dataPtr">A pointer to a struct containing market board purchase information from the server.</param>
|
||||
/// <returns>An object representing the data read.</returns>
|
||||
public static unsafe MarketBoardPurchase Read(IntPtr dataPtr)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
/// <summary>
|
||||
/// Reads market board purchase information from the struct at the provided pointer.
|
||||
/// </summary>
|
||||
/// <param name="dataPtr">A pointer to a struct containing market board purchase information from the server.</param>
|
||||
/// <returns>An object representing the data read.</returns>
|
||||
public static unsafe MarketBoardPurchase Read(IntPtr dataPtr)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
var output = new MarketBoardPurchase();
|
||||
var output = new MarketBoardPurchase();
|
||||
|
||||
output.CatalogId = reader.ReadUInt32();
|
||||
stream.Position += 4;
|
||||
output.ItemQuantity = reader.ReadUInt32();
|
||||
output.CatalogId = reader.ReadUInt32();
|
||||
stream.Position += 4;
|
||||
output.ItemQuantity = reader.ReadUInt32();
|
||||
|
||||
return output;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,61 +1,62 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Dalamud.Game.Network.Structures;
|
||||
|
||||
/// <summary>
|
||||
/// Represents market board purchase information. This message is sent from the
|
||||
/// client when a purchase is made at a market board.
|
||||
/// </summary>
|
||||
internal class MarketBoardPurchaseHandler
|
||||
namespace Dalamud.Game.Network.Structures
|
||||
{
|
||||
private MarketBoardPurchaseHandler()
|
||||
/// <summary>
|
||||
/// Represents market board purchase information. This message is sent from the
|
||||
/// client when a purchase is made at a market board.
|
||||
/// </summary>
|
||||
internal class MarketBoardPurchaseHandler
|
||||
{
|
||||
}
|
||||
private MarketBoardPurchaseHandler()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object ID of the retainer associated with the sale.
|
||||
/// </summary>
|
||||
public ulong RetainerId { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the object ID of the retainer associated with the sale.
|
||||
/// </summary>
|
||||
public ulong RetainerId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object ID of the item listing.
|
||||
/// </summary>
|
||||
public ulong ListingId { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the object ID of the item listing.
|
||||
/// </summary>
|
||||
public ulong ListingId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item ID of the item that was purchased.
|
||||
/// </summary>
|
||||
public uint CatalogId { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the item ID of the item that was purchased.
|
||||
/// </summary>
|
||||
public uint CatalogId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the quantity of the item that was purchased.
|
||||
/// </summary>
|
||||
public uint ItemQuantity { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the quantity of the item that was purchased.
|
||||
/// </summary>
|
||||
public uint ItemQuantity { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unit price of the item.
|
||||
/// </summary>
|
||||
public uint PricePerUnit { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the unit price of the item.
|
||||
/// </summary>
|
||||
public uint PricePerUnit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reads market board purchase information from the struct at the provided pointer.
|
||||
/// </summary>
|
||||
/// <param name="dataPtr">A pointer to a struct containing market board purchase information from the client.</param>
|
||||
/// <returns>An object representing the data read.</returns>
|
||||
public static unsafe MarketBoardPurchaseHandler Read(IntPtr dataPtr)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
/// <summary>
|
||||
/// Reads market board purchase information from the struct at the provided pointer.
|
||||
/// </summary>
|
||||
/// <param name="dataPtr">A pointer to a struct containing market board purchase information from the client.</param>
|
||||
/// <returns>An object representing the data read.</returns>
|
||||
public static unsafe MarketBoardPurchaseHandler Read(IntPtr dataPtr)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
var output = new MarketBoardPurchaseHandler();
|
||||
var output = new MarketBoardPurchaseHandler();
|
||||
|
||||
output.RetainerId = reader.ReadUInt64();
|
||||
output.ListingId = reader.ReadUInt64();
|
||||
output.CatalogId = reader.ReadUInt32();
|
||||
output.ItemQuantity = reader.ReadUInt32();
|
||||
output.PricePerUnit = reader.ReadUInt32();
|
||||
output.RetainerId = reader.ReadUInt64();
|
||||
output.ListingId = reader.ReadUInt64();
|
||||
output.CatalogId = reader.ReadUInt32();
|
||||
output.ItemQuantity = reader.ReadUInt32();
|
||||
output.PricePerUnit = reader.ReadUInt32();
|
||||
|
||||
return output;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,67 +1,68 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Dalamud.Game.Network.Structures;
|
||||
|
||||
/// <summary>
|
||||
/// This class represents the market tax rates from a game network packet.
|
||||
/// </summary>
|
||||
public class MarketTaxRates
|
||||
namespace Dalamud.Game.Network.Structures
|
||||
{
|
||||
private MarketTaxRates()
|
||||
/// <summary>
|
||||
/// This class represents the market tax rates from a game network packet.
|
||||
/// </summary>
|
||||
public class MarketTaxRates
|
||||
{
|
||||
}
|
||||
private MarketTaxRates()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Limsa Lominsa.
|
||||
/// </summary>
|
||||
public uint LimsaLominsaTax { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Limsa Lominsa.
|
||||
/// </summary>
|
||||
public uint LimsaLominsaTax { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Gridania.
|
||||
/// </summary>
|
||||
public uint GridaniaTax { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Gridania.
|
||||
/// </summary>
|
||||
public uint GridaniaTax { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Ul'dah.
|
||||
/// </summary>
|
||||
public uint UldahTax { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Ul'dah.
|
||||
/// </summary>
|
||||
public uint UldahTax { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Ishgard.
|
||||
/// </summary>
|
||||
public uint IshgardTax { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Ishgard.
|
||||
/// </summary>
|
||||
public uint IshgardTax { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Kugane.
|
||||
/// </summary>
|
||||
public uint KuganeTax { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the tax rate in Kugane.
|
||||
/// </summary>
|
||||
public uint KuganeTax { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tax rate in the Crystarium.
|
||||
/// </summary>
|
||||
public uint CrystariumTax { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the tax rate in the Crystarium.
|
||||
/// </summary>
|
||||
public uint CrystariumTax { get; private 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)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
/// <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)
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)dataPtr.ToPointer(), 1544);
|
||||
using var reader = new BinaryReader(stream);
|
||||
|
||||
var output = new MarketTaxRates();
|
||||
var output = new MarketTaxRates();
|
||||
|
||||
stream.Position += 8;
|
||||
output.LimsaLominsaTax = reader.ReadUInt32();
|
||||
output.GridaniaTax = reader.ReadUInt32();
|
||||
output.UldahTax = reader.ReadUInt32();
|
||||
output.IshgardTax = reader.ReadUInt32();
|
||||
output.KuganeTax = reader.ReadUInt32();
|
||||
output.CrystariumTax = reader.ReadUInt32();
|
||||
stream.Position += 8;
|
||||
output.LimsaLominsaTax = reader.ReadUInt32();
|
||||
output.GridaniaTax = reader.ReadUInt32();
|
||||
output.UldahTax = reader.ReadUInt32();
|
||||
output.IshgardTax = reader.ReadUInt32();
|
||||
output.KuganeTax = reader.ReadUInt32();
|
||||
output.CrystariumTax = reader.ReadUInt32();
|
||||
|
||||
return output;
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue