Skip to content

Commit ec59e2e

Browse files
committed
Add support for new trade messages acknowledge
1 parent cfdb8c0 commit ec59e2e

File tree

5 files changed

+60
-1
lines changed

5 files changed

+60
-1
lines changed

ArchiSteamFarm/Steam/Bot.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
164164
[PublicAPI]
165165
public SteamFriends SteamFriends { get; }
166166

167+
[JsonIgnore]
168+
[PublicAPI]
169+
public Trading Trading { get; }
170+
167171
internal bool CanReceiveSteamCards => !IsAccountLimited && !IsAccountLocked;
168172
internal bool HasLoginCodeReady => !string.IsNullOrEmpty(TwoFactorCode) || !string.IsNullOrEmpty(AuthCode);
169173

@@ -179,7 +183,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
179183
private readonly SteamClient SteamClient;
180184
private readonly ConcurrentHashSet<ulong> SteamFamilySharingIDs = [];
181185
private readonly SteamUser SteamUser;
182-
private readonly Trading Trading;
183186
private readonly SemaphoreSlim UnpackBoosterPacksSemaphore = new(1, 1);
184187

185188
private IEnumerable<(string FilePath, EFileType FileType)> RelatedFiles {

ArchiSteamFarm/Steam/Exchange/Trading.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// limitations under the License.
2323

2424
using System;
25+
using System.Collections.Frozen;
2526
using System.Collections.Generic;
2627
using System.Linq;
2728
using System.Threading;
@@ -44,6 +45,9 @@ public sealed class Trading : IDisposable {
4445
internal const byte MaxItemsPerTrade = byte.MaxValue; // This is decided upon various factors, mainly stability of Steam servers when dealing with huge trade offers
4546
internal const byte MaxTradesPerAccount = 5; // This is limit introduced by Valve
4647

48+
[PublicAPI]
49+
public static readonly FrozenSet<uint> TradeRestrictionsAppIDs = [730];
50+
4751
private readonly Bot Bot;
4852
private readonly ConcurrentHashSet<ulong> HandledTradeOfferIDs = [];
4953
private readonly SemaphoreSlim TradesSemaphore = new(1, 1);
@@ -58,6 +62,15 @@ internal Trading(Bot bot) {
5862

5963
public void Dispose() => TradesSemaphore.Dispose();
6064

65+
[PublicAPI]
66+
public async Task<bool> AcknowledgeTradeRestrictions() {
67+
if (Bot.BotDatabase.TradeRestrictionsAcknowledged) {
68+
return true;
69+
}
70+
71+
return Bot.BotDatabase.TradeRestrictionsAcknowledged = await Bot.ArchiWebHandler.AcknowledgeTradeRestrictions().ConfigureAwait(false);
72+
}
73+
6174
[PublicAPI]
6275
public static Dictionary<(uint RealAppID, EAssetType Type, EAssetRarity Rarity), List<uint>> GetInventorySets(IReadOnlyCollection<Asset> inventory) {
6376
if ((inventory == null) || (inventory.Count == 0)) {
@@ -285,6 +298,11 @@ private async Task<bool> ParseActiveTrades() {
285298

286299
IList<ParseTradeResult> tradeResults = await Utilities.InParallel(tasks).ConfigureAwait(false);
287300

301+
if (!Bot.BotDatabase.TradeRestrictionsAcknowledged && tradeResults.Any(static result => ((result.Result == ParseTradeResult.EResult.Accepted) && (result.ItemsToGive?.Any(static item => TradeRestrictionsAppIDs.Contains(item.AppID)) == true)) || (result.ItemsToReceive?.Any(static item => TradeRestrictionsAppIDs.Contains(item.AppID)) == true))) {
302+
// We should normally fail the process in case of a failure here, but since the popup could be marked already in the past, we'll allow it in hope it wasn't needed after all
303+
await AcknowledgeTradeRestrictions().ConfigureAwait(false);
304+
}
305+
288306
if (Bot.HasMobileAuthenticator) {
289307
HashSet<ParseTradeResult> mobileTradeResults = tradeResults.Where(static result => result is { Result: ParseTradeResult.EResult.Accepted, Confirmed: false }).ToHashSet();
290308

ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,17 @@ internal async Task<bool> AcceptDigitalGiftCard(ulong giftCardID) {
15071507
return response?.Content != null ? (true, response.Content.RequiresMobileConfirmation) : (false, false);
15081508
}
15091509

1510+
internal async Task<bool> AcknowledgeTradeRestrictions() {
1511+
Uri request = new(SteamCommunityURL, "/trade/new/acknowledge");
1512+
1513+
// Extra entry for sessionID
1514+
Dictionary<string, string> data = new(2, StringComparer.Ordinal) {
1515+
{ "message", "1" }
1516+
};
1517+
1518+
return await UrlPostWithSession(request, data: data).ConfigureAwait(false);
1519+
}
1520+
15101521
internal async Task<(EResult Result, EPurchaseResultDetail PurchaseResult)> AddFreeLicense(uint subID) {
15111522
ArgumentOutOfRangeException.ThrowIfZero(subID);
15121523

ArchiSteamFarm/Steam/Interaction/Actions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,12 @@ public static (bool Success, string Message) Restart() {
459459
return (false, Strings.BotLootingFailed);
460460
}
461461

462+
// In similar way we might need to accept popup on Steam side, we limit it only to cases that we're aware of, as sending this request otherwise is additional overhead for no reason
463+
if (!Bot.BotDatabase.TradeRestrictionsAcknowledged && items.Any(static item => Trading.TradeRestrictionsAppIDs.Contains(item.AppID))) {
464+
// We should normally fail the process in case of a failure here, but since the popup could be marked already in the past, we'll allow it in hope it wasn't needed after all
465+
await Bot.Trading.AcknowledgeTradeRestrictions().ConfigureAwait(false);
466+
}
467+
462468
(bool success, _, HashSet<ulong>? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(targetSteamID, items, token: tradeToken, customMessage: customMessage, itemsPerTrade: itemsPerTrade).ConfigureAwait(false);
463469

464470
if ((mobileTradeOfferIDs?.Count > 0) && Bot.HasMobileAuthenticator) {

ArchiSteamFarm/Steam/Storage/BotDatabase.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,21 @@ internal uint GamesToRedeemInBackgroundCount {
5050

5151
internal bool HasGamesToRedeemInBackground => GamesToRedeemInBackgroundCount > 0;
5252

53+
[JsonIgnore]
54+
[PublicAPI]
55+
public bool TradeRestrictionsAcknowledged {
56+
get => BackingTradeRestrictionsAcknowledged;
57+
58+
internal set {
59+
if (BackingTradeRestrictionsAcknowledged == value) {
60+
return;
61+
}
62+
63+
BackingTradeRestrictionsAcknowledged = value;
64+
Utilities.InBackground(Save);
65+
}
66+
}
67+
5368
internal string? AccessToken {
5469
get => BackingAccessToken;
5570

@@ -166,6 +181,9 @@ internal string? SteamGuardData {
166181
[JsonInclude]
167182
private string? BackingSteamGuardData { get; set; }
168183

184+
[JsonInclude]
185+
private bool BackingTradeRestrictionsAcknowledged { get; set; }
186+
169187
[JsonDisallowNull]
170188
[JsonInclude]
171189
private OrderedDictionary GamesToRedeemInBackground { get; init; } = new();
@@ -228,6 +246,9 @@ public void SaveToJsonStorage(string key, JsonElement value) {
228246
[UsedImplicitly]
229247
public bool ShouldSerializeBackingSteamGuardData() => !string.IsNullOrEmpty(BackingSteamGuardData);
230248

249+
[UsedImplicitly]
250+
public bool ShouldSerializeBackingTradeRestrictionsAcknowledged() => BackingTradeRestrictionsAcknowledged;
251+
231252
[UsedImplicitly]
232253
public bool ShouldSerializeExtraStorePackages() => ExtraStorePackages.Count > 0;
233254

0 commit comments

Comments
 (0)