mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-16 08:25:28 +00:00
Make descriptions optional, open constructors for plugins
In rare occurances, we might not have a description assigned to the item. This is most notable in inactive trade offers, but we permit this to happen even in inventory fetches. Assigning "default" description is unwanted if caller wants to have a way to determine that description wasn't there to begin with. It makes more sense to make it nullable and *expect* it to be null, then caller can do appropriate checking and decide what they want to do with that. Also open constructors for plugins usage in case they'd like to construct assets manually, e.g. for sending.
This commit is contained in:
@@ -28,45 +28,34 @@ using JetBrains.Annotations;
|
||||
namespace ArchiSteamFarm.Steam.Data;
|
||||
|
||||
// REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_Asset
|
||||
[PublicAPI]
|
||||
public sealed class Asset {
|
||||
[PublicAPI]
|
||||
public const uint SteamAppID = 753;
|
||||
|
||||
[PublicAPI]
|
||||
public const ulong SteamCommunityContextID = 6;
|
||||
|
||||
[PublicAPI]
|
||||
public const ulong SteamPointsShopInstanceID = 3865004543;
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public bool IsSteamPointsShopItem => !Tradable && (InstanceID == SteamPointsShopInstanceID);
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public bool Marketable => Description?.Marketable ?? false;
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public EAssetRarity Rarity => Description?.Rarity ?? EAssetRarity.Unknown;
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public uint RealAppID => Description?.RealAppID ?? 0;
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public bool Tradable => Description?.Tradable ?? false;
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public EAssetType Type => Description?.Type ?? EAssetType.Unknown;
|
||||
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("amount")]
|
||||
[JsonRequired]
|
||||
[PublicAPI]
|
||||
public uint Amount { get; internal set; }
|
||||
|
||||
[JsonInclude]
|
||||
@@ -76,29 +65,24 @@ public sealed class Asset {
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("assetid")]
|
||||
[PublicAPI]
|
||||
public ulong AssetID { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("classid")]
|
||||
[PublicAPI]
|
||||
public ulong ClassID { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("contextid")]
|
||||
[PublicAPI]
|
||||
public ulong ContextID { get; private init; }
|
||||
|
||||
[JsonIgnore]
|
||||
[PublicAPI]
|
||||
public InventoryDescription? Description { get; internal set; }
|
||||
|
||||
[JsonInclude]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
|
||||
[JsonPropertyName("instanceid")]
|
||||
[PublicAPI]
|
||||
public ulong InstanceID { get; private init; }
|
||||
|
||||
[JsonInclude]
|
||||
@@ -109,19 +93,19 @@ public sealed class Asset {
|
||||
init => AssetID = value;
|
||||
}
|
||||
|
||||
internal Asset(uint appID, ulong contextID, ulong classID, uint amount, InventoryDescription description, ulong assetID = 0, ulong instanceID = 0) {
|
||||
[PublicAPI]
|
||||
public Asset(uint appID, ulong contextID, ulong classID, uint amount, InventoryDescription? description = null, ulong assetID = 0, ulong instanceID = 0) {
|
||||
ArgumentOutOfRangeException.ThrowIfZero(appID);
|
||||
ArgumentOutOfRangeException.ThrowIfZero(contextID);
|
||||
ArgumentOutOfRangeException.ThrowIfZero(classID);
|
||||
ArgumentOutOfRangeException.ThrowIfZero(amount);
|
||||
ArgumentNullException.ThrowIfNull(description);
|
||||
|
||||
AppID = appID;
|
||||
ContextID = contextID;
|
||||
ClassID = classID;
|
||||
Amount = amount;
|
||||
Description = description;
|
||||
|
||||
Description = description;
|
||||
AssetID = assetID;
|
||||
InstanceID = instanceID;
|
||||
}
|
||||
|
||||
@@ -512,14 +512,13 @@ public sealed class InventoryDescription {
|
||||
private uint? CachedRealAppID;
|
||||
private EAssetType? CachedType;
|
||||
|
||||
internal InventoryDescription(CEconItem_Description description) {
|
||||
public InventoryDescription(CEconItem_Description description) {
|
||||
ArgumentNullException.ThrowIfNull(description);
|
||||
|
||||
Body = description;
|
||||
}
|
||||
|
||||
// For self-created stubs
|
||||
internal InventoryDescription(uint appID, ulong classID, ulong instanceID = 0, bool marketable = false, bool tradable = false, uint realAppID = 0, EAssetType type = EAssetType.Unknown, EAssetRarity rarity = EAssetRarity.Unknown) {
|
||||
public InventoryDescription(uint appID, ulong classID, ulong instanceID = 0, bool marketable = false, bool tradable = false, uint realAppID = 0, EAssetType type = EAssetType.Unknown, EAssetRarity rarity = EAssetRarity.Unknown) {
|
||||
ArgumentOutOfRangeException.ThrowIfZero(appID);
|
||||
ArgumentOutOfRangeException.ThrowIfZero(classID);
|
||||
|
||||
|
||||
@@ -230,28 +230,15 @@ public sealed class ArchiHandler : ClientMsgHandler {
|
||||
descriptions.Add(key, new InventoryDescription(description));
|
||||
}
|
||||
|
||||
foreach (CEcon_Asset? asset in response.assets) {
|
||||
if (!assetIDs.Add(asset.assetid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(ulong ClassID, ulong InstanceID) key = (asset.classid, asset.instanceid);
|
||||
|
||||
if (!descriptions.TryGetValue(key, out InventoryDescription? description)) {
|
||||
// Best effort only
|
||||
description = new InventoryDescription(appID, asset.classid, asset.instanceid);
|
||||
|
||||
descriptions.Add(key, description);
|
||||
}
|
||||
foreach (CEcon_Asset? asset in response.assets.Where(asset => assetIDs.Add(asset.assetid))) {
|
||||
InventoryDescription? description = descriptions.GetValueOrDefault((asset.classid, asset.instanceid));
|
||||
|
||||
// Extra bulletproofing against Steam showing us middle finger
|
||||
if ((tradableOnly && !description.Tradable) || (marketableOnly && !description.Marketable)) {
|
||||
if ((tradableOnly && (description?.Tradable != true)) || (marketableOnly && (description?.Marketable != true))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Asset convertedAsset = new(asset.appid, asset.contextid, asset.classid, (uint) asset.amount, description, asset.assetid, asset.instanceid);
|
||||
|
||||
yield return convertedAsset;
|
||||
yield return new Asset(asset.appid, asset.contextid, asset.classid, (uint) asset.amount, description, asset.assetid, asset.instanceid);
|
||||
}
|
||||
|
||||
if (!response.more_items) {
|
||||
|
||||
@@ -362,22 +362,11 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||
descriptions.TryAdd(key, description);
|
||||
}
|
||||
|
||||
foreach (Asset asset in response.Content.Assets) {
|
||||
if (!assetIDs.Add(asset.AssetID)) {
|
||||
continue;
|
||||
foreach (Asset asset in response.Content.Assets.Where(asset => assetIDs.Add(asset.AssetID))) {
|
||||
if (descriptions.TryGetValue((asset.ClassID, asset.InstanceID), out InventoryDescription? description)) {
|
||||
asset.Description = description;
|
||||
}
|
||||
|
||||
(ulong ClassID, ulong InstanceID) key = (asset.ClassID, asset.InstanceID);
|
||||
|
||||
if (!descriptions.TryGetValue(key, out InventoryDescription? description)) {
|
||||
// Best effort only
|
||||
description = new InventoryDescription(appID, asset.ClassID, asset.InstanceID);
|
||||
|
||||
descriptions.Add(key, description);
|
||||
}
|
||||
|
||||
asset.Description = description;
|
||||
|
||||
yield return asset;
|
||||
}
|
||||
|
||||
@@ -2390,14 +2379,9 @@ public sealed class ArchiWebHandler : IDisposable {
|
||||
foreach (Asset asset in assets) {
|
||||
(uint AppID, ulong ClassID, ulong InstanceID) key = (asset.AppID, asset.ClassID, asset.InstanceID);
|
||||
|
||||
if (!descriptions.TryGetValue(key, out InventoryDescription? description)) {
|
||||
// Best effort only - we can guarantee tradable property at best, and only at the time of the trade offer
|
||||
description = new InventoryDescription(asset.AppID, asset.ClassID, asset.InstanceID, tradable: true);
|
||||
|
||||
descriptions.Add(key, description);
|
||||
if (descriptions.TryGetValue(key, out InventoryDescription? description)) {
|
||||
asset.Description = description;
|
||||
}
|
||||
|
||||
asset.Description = description;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user