mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 06:00:46 +00:00
Decrease announcement time, set listener for finished trade offers
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -31,6 +31,7 @@ using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
using ArchiSteamFarm.Plugins.Interfaces;
|
||||
using ArchiSteamFarm.Steam;
|
||||
using ArchiSteamFarm.Steam.Exchange;
|
||||
using ArchiSteamFarm.Steam.Integration.Callbacks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
@@ -39,7 +40,7 @@ using SteamKit2;
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
|
||||
|
||||
[Export(typeof(IPlugin))]
|
||||
internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotCommand2, IBotIdentity, IBotModules, IBotUserNotifications {
|
||||
internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotCommand2, IBotIdentity, IBotModules, IBotTradeOfferResults, IBotUserNotifications {
|
||||
internal static readonly ConcurrentDictionary<Bot, RemoteCommunication> RemoteCommunications = new();
|
||||
|
||||
[JsonProperty]
|
||||
@@ -98,6 +99,23 @@ internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotCommand2, I
|
||||
}
|
||||
}
|
||||
|
||||
public Task OnBotTradeOfferResults(Bot bot, IReadOnlyCollection<ParseTradeResult> tradeResults) {
|
||||
ArgumentNullException.ThrowIfNull(bot);
|
||||
|
||||
if ((tradeResults == null) || (tradeResults.Count == 0)) {
|
||||
throw new ArgumentNullException(nameof(tradeResults));
|
||||
}
|
||||
|
||||
// We're interested only in Items notification for Bot that has RemoteCommunication enabled
|
||||
if (!RemoteCommunications.TryGetValue(bot, out RemoteCommunication? remoteCommunication) || !tradeResults.Any(tradeResult => tradeResult is { Result: ParseTradeResult.EResult.Accepted, Confirmed: true } && ((tradeResult.ItemsToGive?.Any(item => bot.BotConfig.MatchableTypes.Contains(item.Type)) == true) || (tradeResult.ItemsToReceive?.Any(item => bot.BotConfig.MatchableTypes.Contains(item.Type)) == true)))) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
remoteCommunication.OnNewItemsNotification();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnBotUserNotifications(Bot bot, IReadOnlyCollection<UserNotificationsCallback.EUserNotification> newNotifications) {
|
||||
ArgumentNullException.ThrowIfNull(bot);
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ using ArchiSteamFarm.Web.Responses;
|
||||
namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
|
||||
|
||||
internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
|
||||
private const byte MaxAnnouncementTTL = 60; // Maximum amount of minutes we can wait before the next Announcement
|
||||
private const byte MaxAnnouncementTTL = 180; // Maximum amount of minutes we can wait before the next Announcement
|
||||
private const byte MinAnnouncementTTL = 5; // Minimum amount of minutes we must wait before the next Announcement
|
||||
private const byte MinHeartBeatTTL = 10; // Minimum amount of minutes we must wait before sending next HeartBeat
|
||||
private const byte MinItemsCount = 100; // Minimum amount of items to be eligible for public listing
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2022 Łukasz "JustArchi" Domeradzki
|
||||
// Copyright 2015-2023 Łukasz "JustArchi" Domeradzki
|
||||
// Contact: JustArchi@JustArchi.net
|
||||
// |
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -21,24 +21,29 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using ArchiSteamFarm.Steam.Data;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ArchiSteamFarm.Steam.Exchange;
|
||||
|
||||
public sealed class ParseTradeResult {
|
||||
[PublicAPI]
|
||||
public IReadOnlyCollection<Asset>? ItemsToGive { get; }
|
||||
|
||||
[PublicAPI]
|
||||
public IReadOnlyCollection<Asset>? ItemsToReceive { get; }
|
||||
|
||||
[PublicAPI]
|
||||
public EResult Result { get; }
|
||||
|
||||
[PublicAPI]
|
||||
public ulong TradeOfferID { get; }
|
||||
|
||||
internal readonly ImmutableHashSet<Asset.EType>? ReceivedItemTypes;
|
||||
[PublicAPI]
|
||||
public bool Confirmed { get; internal set; }
|
||||
|
||||
internal ParseTradeResult(ulong tradeOfferID, EResult result, IReadOnlyCollection<Asset>? itemsToReceive = null) {
|
||||
internal ParseTradeResult(ulong tradeOfferID, EResult result, bool requiresMobileConfirmation, IReadOnlyCollection<Asset>? itemsToGive = null, IReadOnlyCollection<Asset>? itemsToReceive = null) {
|
||||
if (tradeOfferID == 0) {
|
||||
throw new ArgumentOutOfRangeException(nameof(tradeOfferID));
|
||||
}
|
||||
@@ -49,10 +54,9 @@ public sealed class ParseTradeResult {
|
||||
|
||||
TradeOfferID = tradeOfferID;
|
||||
Result = result;
|
||||
|
||||
if (itemsToReceive?.Count > 0) {
|
||||
ReceivedItemTypes = itemsToReceive.Select(static item => item.Type).ToImmutableHashSet();
|
||||
}
|
||||
Confirmed = !requiresMobileConfirmation;
|
||||
ItemsToGive = itemsToGive;
|
||||
ItemsToReceive = itemsToReceive;
|
||||
}
|
||||
|
||||
public enum EResult : byte {
|
||||
|
||||
@@ -424,46 +424,50 @@ public sealed class Trading : IDisposable {
|
||||
HandledTradeOfferIDs.IntersectWith(tradeOffers.Select(static tradeOffer => tradeOffer.TradeOfferID));
|
||||
}
|
||||
|
||||
IEnumerable<Task<(ParseTradeResult? TradeResult, bool RequiresMobileConfirmation)>> tasks = tradeOffers.Where(tradeOffer => !HandledTradeOfferIDs.Contains(tradeOffer.TradeOfferID)).Select(ParseTrade);
|
||||
IList<(ParseTradeResult? TradeResult, bool RequiresMobileConfirmation)> results = await Utilities.InParallel(tasks).ConfigureAwait(false);
|
||||
IEnumerable<Task<ParseTradeResult?>> tasks = tradeOffers.Where(tradeOffer => !HandledTradeOfferIDs.Contains(tradeOffer.TradeOfferID)).Select(ParseTrade);
|
||||
IList<ParseTradeResult?> results = await Utilities.InParallel(tasks).ConfigureAwait(false);
|
||||
|
||||
HashSet<ParseTradeResult> validTradeResults = results.Where(static result => result != null).Select(static result => result!).ToHashSet();
|
||||
|
||||
if (Bot.HasMobileAuthenticator) {
|
||||
HashSet<ulong> mobileTradeOfferIDs = results.Where(static result => (result.TradeResult?.Result == ParseTradeResult.EResult.Accepted) && result.RequiresMobileConfirmation).Select(static result => result.TradeResult!.TradeOfferID).ToHashSet();
|
||||
HashSet<ParseTradeResult> mobileTradeResults = validTradeResults.Where(static result => result is { Result: ParseTradeResult.EResult.Accepted, Confirmed: false }).ToHashSet();
|
||||
|
||||
if (mobileTradeResults.Count > 0) {
|
||||
HashSet<ulong> mobileTradeOfferIDs = mobileTradeResults.Select(static tradeOffer => tradeOffer.TradeOfferID).ToHashSet();
|
||||
|
||||
if (mobileTradeOfferIDs.Count > 0) {
|
||||
(bool twoFactorSuccess, _, _) = await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(true, Confirmation.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false);
|
||||
|
||||
if (!twoFactorSuccess) {
|
||||
if (twoFactorSuccess) {
|
||||
foreach (ParseTradeResult mobileTradeResult in mobileTradeResults) {
|
||||
mobileTradeResult.Confirmed = true;
|
||||
}
|
||||
} else {
|
||||
HandledTradeOfferIDs.ExceptWith(mobileTradeOfferIDs);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HashSet<ParseTradeResult> validTradeResults = results.Where(static result => result.TradeResult != null).Select(static result => result.TradeResult!).ToHashSet();
|
||||
|
||||
if (validTradeResults.Count > 0) {
|
||||
await PluginsCore.OnBotTradeOfferResults(Bot, validTradeResults).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return results.Any(result => (result.TradeResult?.Result == ParseTradeResult.EResult.Accepted) && (!result.RequiresMobileConfirmation || Bot.HasMobileAuthenticator) && (result.TradeResult.ReceivedItemTypes?.Any(receivedItemType => Bot.BotConfig.LootableTypes.Contains(receivedItemType)) == true));
|
||||
return validTradeResults.Any(result => result is { Result: ParseTradeResult.EResult.Accepted, Confirmed: true } && (result.ItemsToReceive?.Any(receivedItem => Bot.BotConfig.LootableTypes.Contains(receivedItem.Type)) == true));
|
||||
}
|
||||
|
||||
private async Task<(ParseTradeResult? TradeResult, bool RequiresMobileConfirmation)> ParseTrade(TradeOffer tradeOffer) {
|
||||
private async Task<ParseTradeResult?> ParseTrade(TradeOffer tradeOffer) {
|
||||
ArgumentNullException.ThrowIfNull(tradeOffer);
|
||||
|
||||
if (tradeOffer.State != ETradeOfferState.Active) {
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, tradeOffer.State));
|
||||
|
||||
return (null, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!HandledTradeOfferIDs.Add(tradeOffer.TradeOfferID)) {
|
||||
// We've already seen this trade, this should not happen
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.IgnoringTrade, tradeOffer.TradeOfferID));
|
||||
|
||||
return (new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.Ignored, tradeOffer.ItemsToReceive), false);
|
||||
return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.Ignored, false, tradeOffer.ItemsToGive, tradeOffer.ItemsToReceive);
|
||||
}
|
||||
|
||||
ParseTradeResult.EResult result = await ShouldAcceptTrade(tradeOffer).ConfigureAwait(false);
|
||||
@@ -523,10 +527,10 @@ public sealed class Trading : IDisposable {
|
||||
default:
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(result), result));
|
||||
|
||||
return (null, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
return (new ParseTradeResult(tradeOffer.TradeOfferID, result, tradeOffer.ItemsToReceive), tradeRequiresMobileConfirmation);
|
||||
return new ParseTradeResult(tradeOffer.TradeOfferID, result, tradeRequiresMobileConfirmation, tradeOffer.ItemsToGive, tradeOffer.ItemsToReceive);
|
||||
}
|
||||
|
||||
private async Task<ParseTradeResult.EResult> ShouldAcceptTrade(TradeOffer tradeOffer) {
|
||||
|
||||
Reference in New Issue
Block a user