mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-18 15:30:30 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af8c48adce | ||
|
|
624a0d9fca | ||
|
|
68e09e786b | ||
|
|
922f572383 | ||
|
|
f19d821388 | ||
|
|
a3f600efd9 | ||
|
|
5cf07ca691 | ||
|
|
dd621a90e4 | ||
|
|
761b46065c | ||
|
|
cfd655b851 | ||
|
|
7c8086d200 | ||
|
|
6e624075e9 | ||
|
|
3c7d4716a6 | ||
|
|
5ca35d0db4 | ||
|
|
430ae31613 | ||
|
|
c8934ab669 |
Submodule ASF-WebConfigGenerator updated: adb2111205...249bf61ca7
2
ASF-ui
2
ASF-ui
Submodule ASF-ui updated: 6e328457f5...ced8221b21
@@ -36,7 +36,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="3.0.0" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2018.3.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.0-preview-20190124-02" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.0-preview-20190203-03" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -28,6 +28,30 @@ using static ArchiSteamFarm.Trading;
|
||||
namespace ArchiSteamFarm.Tests {
|
||||
[TestClass]
|
||||
public sealed class Trading {
|
||||
[TestMethod]
|
||||
public void MismatchRarityIsNotFair() {
|
||||
HashSet<Steam.Asset> itemsToGive = new HashSet<Steam.Asset> { CreateItem(1, rarity: Steam.Asset.ERarity.Rare) };
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(2) };
|
||||
|
||||
Assert.IsFalse(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MismatchRealAppIDsIsNotFair() {
|
||||
HashSet<Steam.Asset> itemsToGive = new HashSet<Steam.Asset> { CreateItem(1, realAppID: 570) };
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(2) };
|
||||
|
||||
Assert.IsFalse(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MismatchTypesIsNotFair() {
|
||||
HashSet<Steam.Asset> itemsToGive = new HashSet<Steam.Asset> { CreateItem(1, type: Steam.Asset.EType.Emoticon) };
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(2) };
|
||||
|
||||
Assert.IsFalse(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MultiGameMultiTypeBadReject() {
|
||||
HashSet<Steam.Asset> inventory = new HashSet<Steam.Asset> {
|
||||
@@ -46,6 +70,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(3, realAppID: 730, type: Steam.Asset.EType.Emoticon)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsFalse(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -66,6 +91,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(4, realAppID: 730, type: Steam.Asset.EType.Emoticon)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -87,6 +113,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(4, realAppID: 730)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsFalse(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -107,6 +134,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(4, realAppID: 730)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -125,6 +153,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(3, type: Steam.Asset.EType.SteamGems)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -146,6 +175,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(3, type: Steam.Asset.EType.Emoticon)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsFalse(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -166,6 +196,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(4, type: Steam.Asset.EType.Emoticon)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -185,6 +216,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(4, 3) };
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsFalse(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -202,6 +234,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(3, 3) };
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsFalse(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -219,6 +252,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(3, 2) };
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -232,6 +266,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
HashSet<Steam.Asset> itemsToGive = new HashSet<Steam.Asset> { CreateItem(1) };
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(2) };
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsFalse(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -250,6 +285,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(3)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsFalse(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -264,6 +300,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
HashSet<Steam.Asset> itemsToGive = new HashSet<Steam.Asset> { CreateItem(2) };
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(3) };
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -287,6 +324,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(4)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsFalse(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -296,6 +334,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
HashSet<Steam.Asset> itemsToGive = new HashSet<Steam.Asset> { CreateItem(1) };
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(2) };
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -305,6 +344,7 @@ namespace ArchiSteamFarm.Tests {
|
||||
HashSet<Steam.Asset> itemsToGive = new HashSet<Steam.Asset> { CreateItem(1) };
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> { CreateItem(2) };
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
@@ -322,10 +362,11 @@ namespace ArchiSteamFarm.Tests {
|
||||
CreateItem(3)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
[NotNull]
|
||||
private static Steam.Asset CreateItem(ulong classID, uint amount = 1, bool marketable = true, uint realAppID = Steam.Asset.SteamAppID, Steam.Asset.EType type = Steam.Asset.EType.TradingCard) => new Steam.Asset(Steam.Asset.SteamAppID, Steam.Asset.SteamCommunityContextID, classID, amount, marketable, realAppID, type);
|
||||
private static Steam.Asset CreateItem(ulong classID, uint amount = 1, bool marketable = true, uint realAppID = Steam.Asset.SteamAppID, Steam.Asset.EType type = Steam.Asset.EType.TradingCard, Steam.Asset.ERarity rarity = Steam.Asset.ERarity.Common) => new Steam.Asset(Steam.Asset.SteamAppID, Steam.Asset.SteamCommunityContextID, classID, amount, marketable, realAppID, type, rarity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,15 +178,13 @@ namespace ArchiSteamFarm {
|
||||
|
||||
ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateVersionInfo, SharedInfo.Version, newVersion));
|
||||
|
||||
if (SharedInfo.Version == newVersion) {
|
||||
return SharedInfo.Version;
|
||||
}
|
||||
|
||||
if (SharedInfo.Version >= newVersion) {
|
||||
if (SharedInfo.Version > newVersion) {
|
||||
ArchiLogger.LogGenericWarning(Strings.WarningPreReleaseVersion);
|
||||
await Task.Delay(15 * 1000).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return SharedInfo.Version;
|
||||
return newVersion;
|
||||
}
|
||||
|
||||
if (!updateOverride && (GlobalConfig.UpdatePeriod == 0)) {
|
||||
|
||||
@@ -250,7 +250,7 @@ namespace ArchiSteamFarm {
|
||||
TradingScheduled = false;
|
||||
}
|
||||
|
||||
HashSet<Steam.Asset> inventory = await Bot.ArchiWebHandler.GetInventory(Bot.SteamID, appID, contextID, true, wantedRealAppIDs, wantedTypes).ConfigureAwait(false);
|
||||
HashSet<Steam.Asset> inventory = await Bot.ArchiWebHandler.GetInventory(Bot.SteamID, appID, contextID, tradable: true, wantedRealAppIDs: wantedRealAppIDs, wantedTypes: wantedTypes).ConfigureAwait(false);
|
||||
|
||||
if ((inventory == null) || (inventory.Count == 0)) {
|
||||
return (false, string.Format(Strings.ErrorIsEmpty, nameof(inventory)));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>ASF.ico</ApplicationIcon>
|
||||
<AssemblyVersion>4.0.0.2</AssemblyVersion>
|
||||
<AssemblyVersion>4.0.0.4</AssemblyVersion>
|
||||
<Authors>JustArchi</Authors>
|
||||
<Company>JustArchi</Company>
|
||||
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
|
||||
@@ -11,7 +11,7 @@
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);config/**;debug/**;out/**;overlay/**</DefaultItemExcludes>
|
||||
<Description>ASF is an application that allows you to farm steam cards using multiple steam accounts simultaneously.</Description>
|
||||
<ErrorReport>none</ErrorReport>
|
||||
<FileVersion>4.0.0.2</FileVersion>
|
||||
<FileVersion>4.0.0.4</FileVersion>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<NoWarn>1591</NoWarn>
|
||||
|
||||
@@ -119,7 +119,7 @@ namespace ArchiSteamFarm {
|
||||
[ItemCanBeNull]
|
||||
[PublicAPI]
|
||||
[SuppressMessage("ReSharper", "FunctionComplexityOverflow")]
|
||||
public async Task<HashSet<Steam.Asset>> GetInventory(ulong steamID = 0, uint appID = Steam.Asset.SteamAppID, uint contextID = Steam.Asset.SteamCommunityContextID, bool? tradable = null, IReadOnlyCollection<uint> wantedRealAppIDs = null, IReadOnlyCollection<Steam.Asset.EType> wantedTypes = null, IReadOnlyCollection<(uint AppID, Steam.Asset.EType Type)> wantedSets = null, IReadOnlyCollection<(uint AppID, Steam.Asset.EType Type)> skippedSets = null) {
|
||||
public async Task<HashSet<Steam.Asset>> GetInventory(ulong steamID = 0, uint appID = Steam.Asset.SteamAppID, uint contextID = Steam.Asset.SteamCommunityContextID, bool? marketable = null, bool? tradable = null, IReadOnlyCollection<uint> wantedRealAppIDs = null, IReadOnlyCollection<Steam.Asset.EType> wantedTypes = null, IReadOnlyCollection<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> wantedSets = null) {
|
||||
if ((appID == 0) || (contextID == 0)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(contextID));
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<ulong, (bool Marketable, bool Tradable, uint RealAppID, Steam.Asset.EType Type)> descriptions = new Dictionary<ulong, (bool Marketable, bool Tradable, uint RealAppID, Steam.Asset.EType Type)>();
|
||||
Dictionary<ulong, (bool Marketable, bool Tradable, uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> descriptions = new Dictionary<ulong, (bool Marketable, bool Tradable, uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)>();
|
||||
|
||||
foreach (Steam.InventoryResponse.Description description in response.Descriptions.Where(description => description != null)) {
|
||||
if (description.ClassID == 0) {
|
||||
@@ -187,25 +187,14 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint realAppID = 0;
|
||||
Steam.Asset.EType type = Steam.Asset.EType.Unknown;
|
||||
uint realAppID = description.RealAppID > 0 ? description.RealAppID : description.AppID;
|
||||
|
||||
if (appID == Steam.Asset.SteamAppID) {
|
||||
if (!string.IsNullOrEmpty(description.MarketHashName)) {
|
||||
realAppID = GetAppIDFromMarketHashName(description.MarketHashName);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(description.Type)) {
|
||||
type = GetItemType(description.Type);
|
||||
}
|
||||
}
|
||||
|
||||
descriptions[description.ClassID] = (description.Marketable, description.Tradable, realAppID, type);
|
||||
descriptions[description.ClassID] = (description.Marketable, description.Tradable, realAppID, description.Type, description.Rarity);
|
||||
}
|
||||
|
||||
foreach (Steam.Asset asset in response.Assets.Where(asset => asset != null)) {
|
||||
if (descriptions.TryGetValue(asset.ClassID, out (bool Marketable, bool Tradable, uint RealAppID, Steam.Asset.EType Type) description)) {
|
||||
if ((tradable.HasValue && (description.Tradable != tradable.Value)) || (wantedRealAppIDs?.Contains(description.RealAppID) == false) || (wantedSets?.Contains((description.RealAppID, description.Type)) == false) || (wantedTypes?.Contains(description.Type) == false) || (skippedSets?.Contains((description.RealAppID, description.Type)) == true)) {
|
||||
if (descriptions.TryGetValue(asset.ClassID, out (bool Marketable, bool Tradable, uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) description)) {
|
||||
if ((marketable.HasValue && (description.Marketable != marketable.Value)) || (tradable.HasValue && (description.Tradable != tradable.Value)) || (wantedRealAppIDs?.Contains(description.RealAppID) == false) || (wantedTypes?.Contains(description.Type) == false) || (wantedSets?.Contains((description.RealAppID, description.Type, description.Rarity)) == false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -213,7 +202,8 @@ namespace ArchiSteamFarm {
|
||||
asset.Tradable = description.Tradable;
|
||||
asset.RealAppID = description.RealAppID;
|
||||
asset.Type = description.Type;
|
||||
} else if (tradable.HasValue || (wantedRealAppIDs != null) || (wantedSets != null) || (wantedTypes != null) || (skippedSets != null)) {
|
||||
asset.Rarity = description.Rarity;
|
||||
} else if (marketable.HasValue || tradable.HasValue || (wantedRealAppIDs != null) || (wantedTypes != null) || (wantedSets != null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1145,7 +1135,7 @@ namespace ArchiSteamFarm {
|
||||
internal HttpClient GenerateDisposableHttpClient() => WebBrowser.GenerateDisposableHttpClient();
|
||||
|
||||
[ItemCanBeNull]
|
||||
internal async Task<HashSet<uint>> GenerateNewDiscoveryQueue() {
|
||||
internal async Task<ImmutableHashSet<uint>> GenerateNewDiscoveryQueue() {
|
||||
const string request = "/explore/generatenewdiscoveryqueue";
|
||||
|
||||
// Extra entry for sessionID
|
||||
@@ -1196,7 +1186,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<(uint AppID, ulong ClassID), (bool Marketable, uint RealAppID, Steam.Asset.EType Type)> descriptions = new Dictionary<(uint AppID, ulong ClassID), (bool Marketable, uint RealAppID, Steam.Asset.EType Type)>();
|
||||
Dictionary<(uint AppID, ulong ClassID), (bool Marketable, uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> descriptions = new Dictionary<(uint AppID, ulong ClassID), (bool Marketable, uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)>();
|
||||
|
||||
foreach (KeyValue description in response["descriptions"].Children) {
|
||||
uint appID = description["appid"].AsUnsignedInteger();
|
||||
@@ -1221,24 +1211,51 @@ namespace ArchiSteamFarm {
|
||||
|
||||
bool marketable = description["marketable"].AsBoolean();
|
||||
|
||||
uint realAppID = 0;
|
||||
uint realAppID = appID;
|
||||
KeyValue marketFeeApp = description["market_fee_app"];
|
||||
|
||||
if (marketFeeApp != KeyValue.Invalid) {
|
||||
realAppID = description["market_fee_app"].AsUnsignedInteger();
|
||||
|
||||
if (realAppID == 0) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(realAppID));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Steam.Asset.EType type = Steam.Asset.EType.Unknown;
|
||||
Steam.Asset.ERarity rarity = Steam.Asset.ERarity.Unknown;
|
||||
|
||||
if (appID == Steam.Asset.SteamAppID) {
|
||||
string hashName = description["market_hash_name"].Value;
|
||||
List<KeyValue> tags = description["tags"].Children;
|
||||
|
||||
if (!string.IsNullOrEmpty(hashName)) {
|
||||
realAppID = GetAppIDFromMarketHashName(hashName);
|
||||
if (tags.Count > 0) {
|
||||
HashSet<Steam.InventoryResponse.Description.Tag> parsedTags = new HashSet<Steam.InventoryResponse.Description.Tag>();
|
||||
|
||||
foreach (KeyValue tag in tags) {
|
||||
string identifier = tag["category"].AsString();
|
||||
|
||||
if (string.IsNullOrEmpty(identifier)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(identifier));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
string descriptionType = description["type"].Value;
|
||||
string value = tag["internal_name"].AsString();
|
||||
|
||||
if (!string.IsNullOrEmpty(descriptionType)) {
|
||||
type = GetItemType(descriptionType);
|
||||
}
|
||||
if (string.IsNullOrEmpty(value)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(value));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
descriptions[(appID, classID)] = (marketable, realAppID, type);
|
||||
parsedTags.Add(new Steam.InventoryResponse.Description.Tag(identifier, value));
|
||||
}
|
||||
|
||||
(type, rarity) = Steam.InventoryResponse.Description.InterpretTags(parsedTags);
|
||||
}
|
||||
|
||||
descriptions[(appID, classID)] = (marketable, realAppID, type, rarity);
|
||||
}
|
||||
|
||||
HashSet<Steam.TradeOffer> result = new HashSet<Steam.TradeOffer>();
|
||||
@@ -1612,7 +1629,7 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
result[appID] = game["name"].Value;
|
||||
result[appID] = game["name"].AsString();
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1911,7 +1928,7 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
string steamLogin = response["token"].Value;
|
||||
string steamLogin = response["token"].AsString();
|
||||
|
||||
if (string.IsNullOrEmpty(steamLogin)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(steamLogin));
|
||||
@@ -1919,7 +1936,7 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
string steamLoginSecure = response["tokensecure"].Value;
|
||||
string steamLoginSecure = response["tokensecure"].AsString();
|
||||
|
||||
if (string.IsNullOrEmpty(steamLoginSecure)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(steamLoginSecure));
|
||||
@@ -2241,76 +2258,6 @@ namespace ArchiSteamFarm {
|
||||
return (ESteamApiKeyState.Registered, text);
|
||||
}
|
||||
|
||||
private static uint GetAppIDFromMarketHashName(string hashName) {
|
||||
if (string.IsNullOrEmpty(hashName)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(hashName));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int index = hashName.IndexOf('-');
|
||||
|
||||
if (index <= 0) {
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(hashName), hashName));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!uint.TryParse(hashName.Substring(0, index), out uint appID) || (appID == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(appID));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return appID;
|
||||
}
|
||||
|
||||
private static Steam.Asset.EType GetItemType(string name) {
|
||||
if (string.IsNullOrEmpty(name)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(name));
|
||||
|
||||
return Steam.Asset.EType.Unknown;
|
||||
}
|
||||
|
||||
switch (name) {
|
||||
case "Booster Pack":
|
||||
|
||||
return Steam.Asset.EType.BoosterPack;
|
||||
case "Steam Gems":
|
||||
|
||||
return Steam.Asset.EType.SteamGems;
|
||||
default:
|
||||
|
||||
if (name.EndsWith("Consumable", StringComparison.Ordinal)) {
|
||||
return Steam.Asset.EType.Consumable;
|
||||
}
|
||||
|
||||
if (name.EndsWith("Emoticon", StringComparison.Ordinal)) {
|
||||
return Steam.Asset.EType.Emoticon;
|
||||
}
|
||||
|
||||
if (name.EndsWith("Foil Trading Card", StringComparison.Ordinal)) {
|
||||
return Steam.Asset.EType.FoilTradingCard;
|
||||
}
|
||||
|
||||
if (name.EndsWith("Profile Background", StringComparison.Ordinal)) {
|
||||
return Steam.Asset.EType.ProfileBackground;
|
||||
}
|
||||
|
||||
if (name.EndsWith("Sale Item", StringComparison.Ordinal)) {
|
||||
return Steam.Asset.EType.SaleItem;
|
||||
}
|
||||
|
||||
if (name.EndsWith("Trading Card", StringComparison.Ordinal)) {
|
||||
return Steam.Asset.EType.TradingCard;
|
||||
}
|
||||
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(name), name));
|
||||
|
||||
return Steam.Asset.EType.Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> IsProfileUri(Uri uri, bool waitForInitialization = true) {
|
||||
if (uri == null) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(uri));
|
||||
@@ -2383,7 +2330,7 @@ namespace ArchiSteamFarm {
|
||||
return uri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal) || uri.Host.Equals("lostauth");
|
||||
}
|
||||
|
||||
private static bool ParseItems(IReadOnlyDictionary<(uint AppID, ulong ClassID), (bool Marketable, uint RealAppID, Steam.Asset.EType Type)> descriptions, IReadOnlyCollection<KeyValue> input, ICollection<Steam.Asset> output) {
|
||||
private static bool ParseItems(IReadOnlyDictionary<(uint AppID, ulong ClassID), (bool Marketable, uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> descriptions, IReadOnlyCollection<KeyValue> input, ICollection<Steam.Asset> output) {
|
||||
if ((descriptions == null) || (input == null) || (input.Count == 0) || (output == null)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(descriptions) + " || " + nameof(input) + " || " + nameof(output));
|
||||
|
||||
@@ -2426,14 +2373,16 @@ namespace ArchiSteamFarm {
|
||||
bool marketable = true;
|
||||
uint realAppID = 0;
|
||||
Steam.Asset.EType type = Steam.Asset.EType.Unknown;
|
||||
Steam.Asset.ERarity rarity = Steam.Asset.ERarity.Unknown;
|
||||
|
||||
if (descriptions.TryGetValue((appID, classID), out (bool Marketable, uint RealAppID, Steam.Asset.EType Type) description)) {
|
||||
if (descriptions.TryGetValue((appID, classID), out (bool Marketable, uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) description)) {
|
||||
marketable = description.Marketable;
|
||||
realAppID = description.RealAppID;
|
||||
type = description.Type;
|
||||
rarity = description.Rarity;
|
||||
}
|
||||
|
||||
Steam.Asset steamAsset = new Steam.Asset(appID, contextID, classID, amount, marketable, realAppID, type);
|
||||
Steam.Asset steamAsset = new Steam.Asset(appID, contextID, classID, amount, marketable, realAppID, type, rarity);
|
||||
output.Add(steamAsset);
|
||||
}
|
||||
|
||||
|
||||
@@ -293,9 +293,15 @@ namespace ArchiSteamFarm {
|
||||
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamParentalCode), SteamParentalCode));
|
||||
}
|
||||
|
||||
foreach (EPermission permission in SteamUserPermissions.Values.Where(permission => !Enum.IsDefined(typeof(EPermission), permission))) {
|
||||
foreach ((ulong steamID, EPermission permission) in SteamUserPermissions) {
|
||||
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
||||
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamUserPermissions), steamID));
|
||||
}
|
||||
|
||||
if (!Enum.IsDefined(typeof(EPermission), permission)) {
|
||||
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamUserPermissions), permission));
|
||||
}
|
||||
}
|
||||
|
||||
return TradingPreferences <= ETradingPreferences.All ? (true, null) : (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(TradingPreferences), TradingPreferences));
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -42,7 +42,7 @@ namespace ArchiSteamFarm {
|
||||
return await GetReleaseFromURL(releaseURL).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
List<ReleaseResponse> response = await GetReleasesFromURL(releaseURL).ConfigureAwait(false);
|
||||
ImmutableList<ReleaseResponse> response = await GetReleasesFromURL(releaseURL).ConfigureAwait(false);
|
||||
|
||||
return response?.FirstOrDefault();
|
||||
}
|
||||
@@ -59,7 +59,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
internal static async Task<List<ReleaseResponse>> GetReleases(byte count) {
|
||||
internal static async Task<ImmutableList<ReleaseResponse>> GetReleases(byte count) {
|
||||
if (count == 0) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(count));
|
||||
|
||||
@@ -104,14 +104,14 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
private static async Task<List<ReleaseResponse>> GetReleasesFromURL(string releaseURL) {
|
||||
private static async Task<ImmutableList<ReleaseResponse>> GetReleasesFromURL(string releaseURL) {
|
||||
if (string.IsNullOrEmpty(nameof(releaseURL))) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(releaseURL));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
WebBrowser.ObjectResponse<List<ReleaseResponse>> objectResponse = await ASF.WebBrowser.UrlGetToJsonObject<List<ReleaseResponse>>(releaseURL).ConfigureAwait(false);
|
||||
WebBrowser.ObjectResponse<ImmutableList<ReleaseResponse>> objectResponse = await ASF.WebBrowser.UrlGetToJsonObject<ImmutableList<ReleaseResponse>>(releaseURL).ConfigureAwait(false);
|
||||
|
||||
return objectResponse?.Content;
|
||||
}
|
||||
@@ -119,7 +119,7 @@ namespace ArchiSteamFarm {
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class ReleaseResponse {
|
||||
[JsonProperty(PropertyName = "assets", Required = Required.Always)]
|
||||
internal readonly HashSet<Asset> Assets;
|
||||
internal readonly ImmutableHashSet<Asset> Assets;
|
||||
|
||||
[JsonProperty(PropertyName = "prerelease", Required = Required.Always)]
|
||||
internal readonly bool IsPreRelease;
|
||||
|
||||
@@ -257,6 +257,10 @@ namespace ArchiSteamFarm {
|
||||
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamMessagePrefix), SteamMessagePrefix));
|
||||
}
|
||||
|
||||
if ((SteamOwnerID != 0) && !new SteamID(SteamOwnerID).IsIndividualAccount) {
|
||||
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamOwnerID), SteamOwnerID));
|
||||
}
|
||||
|
||||
if ((SteamProtocols <= 0) || (SteamProtocols > ProtocolTypes.All)) {
|
||||
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamProtocols), SteamProtocols));
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -79,7 +80,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
|
||||
return BadRequest(new GenericResponse<IReadOnlyCollection<GitHubReleaseResponse>>(false, string.Format(Strings.ErrorIsEmpty, nameof(count))));
|
||||
}
|
||||
|
||||
List<GitHub.ReleaseResponse> response = await GitHub.GetReleases(count).ConfigureAwait(false);
|
||||
ImmutableList<GitHub.ReleaseResponse> response = await GitHub.GetReleases(count).ConfigureAwait(false);
|
||||
|
||||
if ((response == null) || (response.Count == 0)) {
|
||||
return BadRequest(new GenericResponse<IReadOnlyCollection<GitHub.ReleaseResponse>>(false, string.Format(Strings.ErrorRequestFailedTooManyTimes, WebBrowser.MaxTries)));
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using ArchiSteamFarm.Localization;
|
||||
@@ -57,6 +58,9 @@ namespace ArchiSteamFarm.Json {
|
||||
[PublicAPI]
|
||||
public bool Marketable { get; internal set; }
|
||||
|
||||
[PublicAPI]
|
||||
public ERarity Rarity { get; internal set; }
|
||||
|
||||
[PublicAPI]
|
||||
public uint RealAppID { get; internal set; }
|
||||
|
||||
@@ -160,7 +164,7 @@ namespace ArchiSteamFarm.Json {
|
||||
}
|
||||
|
||||
// Constructed from trades being received or plugins
|
||||
public Asset(uint appID, uint contextID, ulong classID, uint amount, bool marketable = true, uint realAppID = 0, EType type = EType.Unknown) {
|
||||
public Asset(uint appID, uint contextID, ulong classID, uint amount, bool marketable = true, uint realAppID = 0, EType type = EType.Unknown, ERarity rarity = ERarity.Unknown) {
|
||||
if ((appID == 0) || (contextID == 0) || (classID == 0) || (amount == 0)) {
|
||||
throw new ArgumentNullException(nameof(appID) + " || " + nameof(contextID) + " || " + nameof(classID) + " || " + nameof(amount));
|
||||
}
|
||||
@@ -172,11 +176,19 @@ namespace ArchiSteamFarm.Json {
|
||||
Marketable = marketable;
|
||||
RealAppID = realAppID;
|
||||
Type = type;
|
||||
Rarity = rarity;
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
private Asset() { }
|
||||
|
||||
public enum ERarity : byte {
|
||||
Unknown,
|
||||
Common,
|
||||
Uncommon,
|
||||
Rare
|
||||
}
|
||||
|
||||
public enum EType : byte {
|
||||
Unknown,
|
||||
BoosterPack,
|
||||
@@ -186,7 +198,8 @@ namespace ArchiSteamFarm.Json {
|
||||
TradingCard,
|
||||
SteamGems,
|
||||
SaleItem,
|
||||
Consumable
|
||||
Consumable,
|
||||
ProfileModifier
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,10 +404,10 @@ namespace ArchiSteamFarm.Json {
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class InventoryResponse : NumberResponse {
|
||||
[JsonProperty(PropertyName = "assets", Required = Required.DisallowNull)]
|
||||
internal readonly HashSet<Asset> Assets;
|
||||
internal readonly ImmutableHashSet<Asset> Assets;
|
||||
|
||||
[JsonProperty(PropertyName = "descriptions", Required = Required.DisallowNull)]
|
||||
internal readonly HashSet<Description> Descriptions;
|
||||
internal readonly ImmutableHashSet<Description> Descriptions;
|
||||
|
||||
[JsonProperty(PropertyName = "error", Required = Required.DisallowNull)]
|
||||
internal readonly string Error;
|
||||
@@ -436,15 +449,14 @@ namespace ArchiSteamFarm.Json {
|
||||
[JsonProperty(PropertyName = "appid", Required = Required.Always)]
|
||||
internal readonly uint AppID;
|
||||
|
||||
[JsonProperty(PropertyName = "market_hash_name", Required = Required.Always)]
|
||||
internal readonly string MarketHashName;
|
||||
|
||||
[JsonProperty(PropertyName = "type", Required = Required.Always)]
|
||||
internal readonly string Type;
|
||||
[JsonProperty(PropertyName = "market_fee_app", Required = Required.DisallowNull)]
|
||||
internal readonly uint RealAppID;
|
||||
|
||||
internal ulong ClassID { get; private set; }
|
||||
internal bool Marketable { get; private set; }
|
||||
internal Asset.ERarity Rarity { get; private set; }
|
||||
internal bool Tradable { get; private set; }
|
||||
internal Asset.EType Type { get; private set; }
|
||||
|
||||
[JsonProperty(PropertyName = "classid", Required = Required.Always)]
|
||||
private string ClassIDText {
|
||||
@@ -470,6 +482,19 @@ namespace ArchiSteamFarm.Json {
|
||||
set => Marketable = value > 0;
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "tags", Required = Required.DisallowNull)]
|
||||
private ImmutableHashSet<Tag> Tags {
|
||||
set {
|
||||
if ((value == null) || (value.Count == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(value));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
(Type, Rarity) = InterpretTags(value);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty(PropertyName = "tradable", Required = Required.Always)]
|
||||
private byte TradableNumber {
|
||||
set => Tradable = value > 0;
|
||||
@@ -477,13 +502,137 @@ namespace ArchiSteamFarm.Json {
|
||||
|
||||
[JsonConstructor]
|
||||
private Description() { }
|
||||
|
||||
internal static (Asset.EType Type, Asset.ERarity Rarity) InterpretTags(IReadOnlyCollection<Tag> tags) {
|
||||
if ((tags == null) || (tags.Count == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(tags));
|
||||
|
||||
return (Asset.EType.Unknown, Asset.ERarity.Unknown);
|
||||
}
|
||||
|
||||
Asset.EType type = Asset.EType.Unknown;
|
||||
Asset.ERarity rarity = Asset.ERarity.Unknown;
|
||||
|
||||
foreach (Tag tag in tags) {
|
||||
switch (tag.Identifier) {
|
||||
case "cardborder":
|
||||
|
||||
switch (tag.Value) {
|
||||
case "cardborder_0":
|
||||
type = Asset.EType.TradingCard;
|
||||
|
||||
break;
|
||||
case "cardborder_1":
|
||||
type = Asset.EType.FoilTradingCard;
|
||||
|
||||
break;
|
||||
default:
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(tag.Value), tag.Value));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case "droprate":
|
||||
|
||||
switch (tag.Value) {
|
||||
case "droprate_0":
|
||||
rarity = Asset.ERarity.Common;
|
||||
|
||||
break;
|
||||
case "droprate_1":
|
||||
rarity = Asset.ERarity.Uncommon;
|
||||
|
||||
break;
|
||||
case "droprate_2":
|
||||
rarity = Asset.ERarity.Rare;
|
||||
|
||||
break;
|
||||
default:
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(tag.Value), tag.Value));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case "item_class":
|
||||
|
||||
switch (tag.Value) {
|
||||
case "item_class_2":
|
||||
|
||||
// This is a fallback in case we'd have no cardborder available to interpret
|
||||
if (type == Asset.EType.Unknown) {
|
||||
type = Asset.EType.TradingCard;
|
||||
}
|
||||
|
||||
break;
|
||||
case "item_class_3":
|
||||
type = Asset.EType.ProfileBackground;
|
||||
|
||||
break;
|
||||
case "item_class_4":
|
||||
type = Asset.EType.Emoticon;
|
||||
|
||||
break;
|
||||
case "item_class_5":
|
||||
type = Asset.EType.BoosterPack;
|
||||
|
||||
break;
|
||||
case "item_class_6":
|
||||
type = Asset.EType.Consumable;
|
||||
|
||||
break;
|
||||
case "item_class_7":
|
||||
type = Asset.EType.SteamGems;
|
||||
|
||||
break;
|
||||
case "item_class_8":
|
||||
type = Asset.EType.ProfileModifier;
|
||||
|
||||
break;
|
||||
case "item_class_10":
|
||||
type = Asset.EType.SaleItem;
|
||||
|
||||
break;
|
||||
default:
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(tag.Value), tag.Value));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (type, rarity);
|
||||
}
|
||||
|
||||
internal sealed class Tag {
|
||||
[JsonProperty(PropertyName = "category", Required = Required.Always)]
|
||||
internal readonly string Identifier;
|
||||
|
||||
[JsonProperty(PropertyName = "internal_name", Required = Required.Always)]
|
||||
internal readonly string Value;
|
||||
|
||||
internal Tag([NotNull] string identifier, [NotNull] string value) {
|
||||
if (string.IsNullOrEmpty(identifier) || string.IsNullOrEmpty(value)) {
|
||||
throw new ArgumentNullException(nameof(identifier) + " || " + nameof(value));
|
||||
}
|
||||
|
||||
Identifier = identifier;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
private Tag() { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class NewDiscoveryQueueResponse {
|
||||
[JsonProperty(PropertyName = "queue", Required = Required.Always)]
|
||||
internal readonly HashSet<uint> Queue;
|
||||
internal readonly ImmutableHashSet<uint> Queue;
|
||||
|
||||
[JsonConstructor]
|
||||
private NewDiscoveryQueueResponse() { }
|
||||
|
||||
@@ -184,10 +184,10 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
private async Task<HashSet<ListedUser>> GetListedUsers() {
|
||||
private async Task<ImmutableHashSet<ListedUser>> GetListedUsers() {
|
||||
const string request = URL + "/Api/Bots";
|
||||
|
||||
WebBrowser.ObjectResponse<HashSet<ListedUser>> objectResponse = await Bot.ArchiWebHandler.WebBrowser.UrlGetToJsonObject<HashSet<ListedUser>>(request).ConfigureAwait(false);
|
||||
WebBrowser.ObjectResponse<ImmutableHashSet<ListedUser>> objectResponse = await Bot.ArchiWebHandler.WebBrowser.UrlGetToJsonObject<ImmutableHashSet<ListedUser>>(request).ConfigureAwait(false);
|
||||
|
||||
return objectResponse?.Content;
|
||||
}
|
||||
@@ -300,7 +300,7 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
(Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> fullState, Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> tradableState) = Trading.GetDividedInventoryState(ourInventory);
|
||||
(Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> fullState, Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> tradableState) = Trading.GetDividedInventoryState(ourInventory);
|
||||
|
||||
if (Trading.IsEmptyForMatching(fullState, tradableState)) {
|
||||
// User doesn't have any more dupes in the inventory
|
||||
@@ -309,7 +309,7 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
HashSet<ListedUser> listedUsers = await GetListedUsers().ConfigureAwait(false);
|
||||
ImmutableHashSet<ListedUser> listedUsers = await GetListedUsers().ConfigureAwait(false);
|
||||
|
||||
if ((listedUsers == null) || (listedUsers.Count == 0)) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(listedUsers)));
|
||||
@@ -318,12 +318,18 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
byte emptyMatches = 0;
|
||||
HashSet<(uint AppID, Steam.Asset.EType Type)> skippedSetsThisRound = new HashSet<(uint AppID, Steam.Asset.EType Type)>();
|
||||
HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> skippedSetsThisRound = new HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)>();
|
||||
|
||||
foreach (ListedUser listedUser in listedUsers.Where(listedUser => listedUser.MatchEverything && acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && (!triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) || (attempt.Tries < byte.MaxValue)) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderBy(listedUser => triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) ? attempt.Tries : 0).ThenByDescending(listedUser => listedUser.Score).Take(MaxMatchedBotsHard)) {
|
||||
HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> wantedSets = tradableState.Keys.Where(set => !skippedSetsThisRound.Contains(set) && listedUser.MatchableTypes.Contains(set.Type)).ToHashSet();
|
||||
|
||||
if (wantedSets.Count == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Bot.ArchiLogger.LogGenericTrace(listedUser.SteamID + "...");
|
||||
|
||||
HashSet<Steam.Asset> theirInventory = await Bot.ArchiWebHandler.GetInventory(listedUser.SteamID, tradable: true, wantedSets: fullState.Keys, skippedSets: skippedSetsThisRound).ConfigureAwait(false);
|
||||
HashSet<Steam.Asset> theirInventory = await Bot.ArchiWebHandler.GetInventory(listedUser.SteamID, tradable: true, wantedSets: wantedSets).ConfigureAwait(false);
|
||||
|
||||
if ((theirInventory == null) || (theirInventory.Count == 0)) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(theirInventory)));
|
||||
@@ -331,19 +337,19 @@ namespace ArchiSteamFarm {
|
||||
continue;
|
||||
}
|
||||
|
||||
HashSet<(uint AppID, Steam.Asset.EType Type)> skippedSetsThisUser = new HashSet<(uint AppID, Steam.Asset.EType Type)>();
|
||||
HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> skippedSetsThisUser = new HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)>();
|
||||
|
||||
Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> theirTradableState = Trading.GetInventoryState(theirInventory);
|
||||
Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> inventoryStateChanges = new Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>>();
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> theirTradableState = Trading.GetInventoryState(theirInventory);
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> inventoryStateChanges = new Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>>();
|
||||
|
||||
for (byte i = 0; i < Trading.MaxTradesPerAccount; i++) {
|
||||
byte itemsInTrade = 0;
|
||||
HashSet<(uint AppID, Steam.Asset.EType Type)> skippedSetsThisTrade = new HashSet<(uint AppID, Steam.Asset.EType Type)>();
|
||||
HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> skippedSetsThisTrade = new HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)>();
|
||||
|
||||
Dictionary<ulong, uint> classIDsToGive = new Dictionary<ulong, uint>();
|
||||
Dictionary<ulong, uint> classIDsToReceive = new Dictionary<ulong, uint>();
|
||||
|
||||
foreach (((uint AppID, Steam.Asset.EType Type) set, Dictionary<ulong, uint> ourFullItems) in fullState.Where(set => !skippedSetsThisUser.Contains(set.Key) && listedUser.MatchableTypes.Contains(set.Key.Type) && set.Value.Values.Any(count => count > 1))) {
|
||||
foreach (((uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) set, Dictionary<ulong, uint> ourFullItems) in fullState.Where(set => !skippedSetsThisUser.Contains(set.Key) && listedUser.MatchableTypes.Contains(set.Key.Type) && set.Value.Values.Any(count => count > 1))) {
|
||||
if (!tradableState.TryGetValue(set, out Dictionary<ulong, uint> ourTradableItems) || (ourTradableItems.Count == 0)) {
|
||||
continue;
|
||||
}
|
||||
@@ -473,7 +479,7 @@ namespace ArchiSteamFarm {
|
||||
HashSet<Steam.Asset> itemsToGive = Trading.GetTradableItemsFromInventory(ourInventory, classIDsToGive);
|
||||
HashSet<Steam.Asset> itemsToReceive = Trading.GetTradableItemsFromInventory(theirInventory, classIDsToReceive);
|
||||
|
||||
if ((itemsToGive.Count != itemsToReceive.Count) || !Trading.IsFairTypesExchange(itemsToGive, itemsToReceive)) {
|
||||
if ((itemsToGive.Count != itemsToReceive.Count) || !Trading.IsFairExchange(itemsToGive, itemsToReceive)) {
|
||||
// Failsafe
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningFailedWithError, Strings.ErrorAborted));
|
||||
|
||||
@@ -538,7 +544,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
skippedSetsThisRound.UnionWith(skippedSetsThisUser);
|
||||
|
||||
foreach ((uint AppID, Steam.Asset.EType Type) skippedSet in skippedSetsThisUser) {
|
||||
foreach ((uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) skippedSet in skippedSetsThisUser) {
|
||||
fullState.Remove(skippedSet);
|
||||
tradableState.Remove(skippedSet);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Localization;
|
||||
@@ -55,7 +55,7 @@ namespace ArchiSteamFarm {
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.Starting);
|
||||
|
||||
for (byte i = 0; (i < MaxSingleQueuesDaily) && (await IsDiscoveryQueueAvailable().ConfigureAwait(false)).GetValueOrDefault(); i++) {
|
||||
HashSet<uint> queue = await Bot.ArchiWebHandler.GenerateNewDiscoveryQueue().ConfigureAwait(false);
|
||||
ImmutableHashSet<uint> queue = await Bot.ArchiWebHandler.GenerateNewDiscoveryQueue().ConfigureAwait(false);
|
||||
|
||||
if ((queue == null) || (queue.Count == 0)) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(queue)));
|
||||
|
||||
@@ -46,50 +46,32 @@ namespace ArchiSteamFarm {
|
||||
public void Dispose() => TradesSemaphore.Dispose();
|
||||
|
||||
[PublicAPI]
|
||||
public static bool IsFairTypesExchange(IReadOnlyCollection<Steam.Asset> itemsToGive, IReadOnlyCollection<Steam.Asset> itemsToReceive) {
|
||||
public static bool IsFairExchange(IReadOnlyCollection<Steam.Asset> itemsToGive, IReadOnlyCollection<Steam.Asset> itemsToReceive) {
|
||||
if ((itemsToGive == null) || (itemsToGive.Count == 0) || (itemsToReceive == null) || (itemsToReceive.Count == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(itemsToGive) + " || " + nameof(itemsToReceive));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Dictionary<uint, Dictionary<Steam.Asset.EType, uint>> itemsToGivePerGame = new Dictionary<uint, Dictionary<Steam.Asset.EType, uint>>();
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), uint> itemsToGiveAmounts = new Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), uint>();
|
||||
|
||||
foreach (Steam.Asset item in itemsToGive) {
|
||||
if (itemsToGivePerGame.TryGetValue(item.RealAppID, out Dictionary<Steam.Asset.EType, uint> itemsPerType)) {
|
||||
itemsPerType[item.Type] = itemsPerType.TryGetValue(item.Type, out uint amount) ? amount + item.Amount : item.Amount;
|
||||
} else {
|
||||
itemsPerType = new Dictionary<Steam.Asset.EType, uint> { [item.Type] = item.Amount };
|
||||
itemsToGivePerGame[item.RealAppID] = itemsPerType;
|
||||
}
|
||||
(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) key = (item.RealAppID, item.Type, item.Rarity);
|
||||
itemsToGiveAmounts[key] = itemsToGiveAmounts.TryGetValue(key, out uint amount) ? amount + item.Amount : item.Amount;
|
||||
}
|
||||
|
||||
Dictionary<uint, Dictionary<Steam.Asset.EType, uint>> itemsToReceivePerGame = new Dictionary<uint, Dictionary<Steam.Asset.EType, uint>>();
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), uint> itemsToReceiveAmounts = new Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), uint>();
|
||||
|
||||
foreach (Steam.Asset item in itemsToReceive) {
|
||||
if (itemsToReceivePerGame.TryGetValue(item.RealAppID, out Dictionary<Steam.Asset.EType, uint> itemsPerType)) {
|
||||
itemsPerType[item.Type] = itemsPerType.TryGetValue(item.Type, out uint amount) ? amount + item.Amount : item.Amount;
|
||||
} else {
|
||||
itemsPerType = new Dictionary<Steam.Asset.EType, uint> { [item.Type] = item.Amount };
|
||||
itemsToReceivePerGame[item.RealAppID] = itemsPerType;
|
||||
}
|
||||
(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) key = (item.RealAppID, item.Type, item.Rarity);
|
||||
itemsToReceiveAmounts[key] = itemsToReceiveAmounts.TryGetValue(key, out uint amount) ? amount + item.Amount : item.Amount;
|
||||
}
|
||||
|
||||
// Ensure that amount of items to give is at least amount of items to receive (per game and per type)
|
||||
foreach ((uint appID, Dictionary<Steam.Asset.EType, uint> itemsPerGame) in itemsToGivePerGame) {
|
||||
if (!itemsToReceivePerGame.TryGetValue(appID, out Dictionary<Steam.Asset.EType, uint> otherItemsPerType)) {
|
||||
// Ensure that amount of items to give is at least amount of items to receive (per all fairness factors)
|
||||
foreach (((uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) key, uint amountToGive) in itemsToGiveAmounts) {
|
||||
if (!itemsToReceiveAmounts.TryGetValue(key, out uint amountToReceive) || (amountToGive > amountToReceive)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ((Steam.Asset.EType type, uint amount) in itemsPerGame) {
|
||||
if (!otherItemsPerType.TryGetValue(type, out uint otherAmount)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (amount > otherAmount) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -109,7 +91,7 @@ namespace ArchiSteamFarm {
|
||||
// All of those cases should be verified by our unit tests to ensure that the logic here matches all possible cases, especially those that were incorrectly handled previously
|
||||
|
||||
// Firstly we get initial sets state of our inventory
|
||||
Dictionary<(uint AppID, Steam.Asset.EType Type), List<uint>> initialSets = GetInventorySets(inventory);
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), List<uint>> initialSets = GetInventorySets(inventory);
|
||||
|
||||
// Once we have initial state, we remove items that we're supposed to give from our inventory
|
||||
// This loop is a bit more complex due to the fact that we might have a mix of the same item splitted into different amounts
|
||||
@@ -149,10 +131,10 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// Now we can get final sets state of our inventory after the exchange
|
||||
Dictionary<(uint AppID, Steam.Asset.EType Type), List<uint>> finalSets = GetInventorySets(inventory);
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), List<uint>> finalSets = GetInventorySets(inventory);
|
||||
|
||||
// Once we have both states, we can check overall fairness
|
||||
foreach (((uint AppID, Steam.Asset.EType Type) set, List<uint> beforeAmounts) in initialSets) {
|
||||
foreach (((uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) set, List<uint> beforeAmounts) in initialSets) {
|
||||
if (!finalSets.TryGetValue(set, out List<uint> afterAmounts)) {
|
||||
// If we have no info about this set, then it has to be a bad one
|
||||
return false;
|
||||
@@ -201,18 +183,18 @@ namespace ArchiSteamFarm {
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static (Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> FullState, Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> TradableState) GetDividedInventoryState(IReadOnlyCollection<Steam.Asset> inventory) {
|
||||
internal static (Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> FullState, Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> TradableState) GetDividedInventoryState(IReadOnlyCollection<Steam.Asset> inventory) {
|
||||
if ((inventory == null) || (inventory.Count == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(inventory));
|
||||
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> fullState = new Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>>();
|
||||
Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> tradableState = new Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>>();
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> fullState = new Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>>();
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> tradableState = new Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>>();
|
||||
|
||||
foreach (Steam.Asset item in inventory) {
|
||||
(uint RealAppID, Steam.Asset.EType Type) key = (item.RealAppID, item.Type);
|
||||
(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) key = (item.RealAppID, item.Type, item.Rarity);
|
||||
|
||||
if (fullState.TryGetValue(key, out Dictionary<ulong, uint> fullSet)) {
|
||||
if (fullSet.TryGetValue(item.ClassID, out uint amount)) {
|
||||
@@ -242,17 +224,17 @@ namespace ArchiSteamFarm {
|
||||
return (fullState, tradableState);
|
||||
}
|
||||
|
||||
internal static Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> GetInventoryState(IReadOnlyCollection<Steam.Asset> inventory) {
|
||||
internal static Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> GetInventoryState(IReadOnlyCollection<Steam.Asset> inventory) {
|
||||
if ((inventory == null) || (inventory.Count == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(inventory));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> state = new Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>>();
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> state = new Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>>();
|
||||
|
||||
foreach (Steam.Asset item in inventory) {
|
||||
(uint RealAppID, Steam.Asset.EType Type) key = (item.RealAppID, item.Type);
|
||||
(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) key = (item.RealAppID, item.Type, item.Rarity);
|
||||
|
||||
if (state.TryGetValue(key, out Dictionary<ulong, uint> set)) {
|
||||
if (set.TryGetValue(item.ClassID, out uint amount)) {
|
||||
@@ -298,14 +280,14 @@ namespace ArchiSteamFarm {
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static bool IsEmptyForMatching(IReadOnlyDictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> fullState, IReadOnlyDictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> tradableState) {
|
||||
internal static bool IsEmptyForMatching(IReadOnlyDictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> fullState, IReadOnlyDictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> tradableState) {
|
||||
if ((fullState == null) || (tradableState == null)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(fullState) + " || " + nameof(tradableState));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (((uint AppID, Steam.Asset.EType Type) set, Dictionary<ulong, uint> state) in tradableState) {
|
||||
foreach (((uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity) set, Dictionary<ulong, uint> state) in tradableState) {
|
||||
if (!fullState.TryGetValue(set, out Dictionary<ulong, uint> fullSet) || (fullSet == null) || (fullSet.Count == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(fullSet));
|
||||
|
||||
@@ -391,14 +373,14 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<(uint AppID, Steam.Asset.EType Type), List<uint>> GetInventorySets(IReadOnlyCollection<Steam.Asset> inventory) {
|
||||
private static Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), List<uint>> GetInventorySets(IReadOnlyCollection<Steam.Asset> inventory) {
|
||||
if ((inventory == null) || (inventory.Count == 0)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(inventory));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<(uint AppID, Steam.Asset.EType Type), Dictionary<ulong, uint>> sets = GetInventoryState(inventory);
|
||||
Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> sets = GetInventoryState(inventory);
|
||||
|
||||
return sets.ToDictionary(set => set.Key, set => set.Value.Values.OrderBy(amount => amount).ToList());
|
||||
}
|
||||
@@ -582,7 +564,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// Decline trade if we're requested to handle any not-accepted item type or if it's not fair games/types exchange
|
||||
if (!tradeOffer.IsValidSteamItemsRequest(Bot.BotConfig.MatchableTypes) || !IsFairTypesExchange(tradeOffer.ItemsToGive, tradeOffer.ItemsToReceive)) {
|
||||
if (!tradeOffer.IsValidSteamItemsRequest(Bot.BotConfig.MatchableTypes) || !IsFairExchange(tradeOffer.ItemsToGive, tradeOffer.ItemsToReceive)) {
|
||||
return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.Rejected, tradeOffer.ItemsToReceive);
|
||||
}
|
||||
|
||||
@@ -610,10 +592,10 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// Get sets we're interested in
|
||||
HashSet<(uint AppID, Steam.Asset.EType Type)> wantedSets = new HashSet<(uint AppID, Steam.Asset.EType Type)>();
|
||||
HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> wantedSets = new HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)>();
|
||||
|
||||
foreach (Steam.Asset item in tradeOffer.ItemsToGive) {
|
||||
wantedSets.Add((item.RealAppID, item.Type));
|
||||
wantedSets.Add((item.RealAppID, item.Type, item.Rarity));
|
||||
}
|
||||
|
||||
// Now check if it's worth for us to do the trade
|
||||
|
||||
2
wiki
2
wiki
Submodule wiki updated: 92db2be904...12ba9edb75
Reference in New Issue
Block a user