diff --git a/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj b/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj new file mode 100644 index 000000000..201aa7a0b --- /dev/null +++ b/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj @@ -0,0 +1,29 @@ + + + + Exe + netcoreapp2.0 + latest + none + + + + none + false + + + + + + + + + + + + + + + + + diff --git a/ArchiSteamFarm.Tests/Trading.cs b/ArchiSteamFarm.Tests/Trading.cs new file mode 100644 index 000000000..220854d92 --- /dev/null +++ b/ArchiSteamFarm.Tests/Trading.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using ArchiSteamFarm.JSON; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ArchiSteamFarm.Tests { + [TestClass] + public sealed class Trading { + [TestMethod] + public void TradingMultiGameBadReject() { + Steam.Item item1Game1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 570, Steam.Item.EType.TradingCard); + Steam.Item item1Game1X9 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 9, 570, Steam.Item.EType.TradingCard); + Steam.Item item2Game1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 570, Steam.Item.EType.TradingCard); + + Steam.Item item1Game2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 3, 1, 730, Steam.Item.EType.TradingCard); + Steam.Item item2Game2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 4, 1, 730, Steam.Item.EType.TradingCard); + + HashSet inventory = new HashSet { item1Game1X9, item1Game2, item2Game2 }; + HashSet itemsToGive = new HashSet { item1Game1, item1Game2 }; + HashSet itemsToReceive = new HashSet { item2Game1, item2Game2 }; + + Assert.IsFalse(AcceptsTrade(inventory, itemsToGive, itemsToReceive)); + } + + [TestMethod] + public void TradingMultiGameMultiTypeBadReject() { + Steam.Item item1Type1Game1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 570, Steam.Item.EType.TradingCard); + Steam.Item item1Type1Game1X9 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 9, 570, Steam.Item.EType.TradingCard); + Steam.Item item2Type1Game1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 570, Steam.Item.EType.TradingCard); + + Steam.Item item3Type2Game2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 3, 1, 730, Steam.Item.EType.Emoticon); + Steam.Item item3Type2Game2X9 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 3, 9, 730, Steam.Item.EType.Emoticon); + Steam.Item item4Type2Game2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 4, 1, 730, Steam.Item.EType.Emoticon); + + HashSet inventory = new HashSet { item1Type1Game1X9, item3Type2Game2X9, item4Type2Game2 }; + HashSet itemsToGive = new HashSet { item1Type1Game1, item4Type2Game2 }; + HashSet itemsToReceive = new HashSet { item2Type1Game1, item3Type2Game2 }; + + Assert.IsFalse(AcceptsTrade(inventory, itemsToGive, itemsToReceive)); + } + + [TestMethod] + public void TradingMultiGameMultiTypeNeutralAccept() { + Steam.Item item1Type1Game1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 570, Steam.Item.EType.TradingCard); + Steam.Item item1Type1Game1X9 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 9, 570, Steam.Item.EType.TradingCard); + Steam.Item item2Type1Game1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 570, Steam.Item.EType.TradingCard); + + Steam.Item item3Type2Game2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 3, 1, 730, Steam.Item.EType.Emoticon); + Steam.Item item4Type2Game2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 4, 1, 730, Steam.Item.EType.Emoticon); + + HashSet inventory = new HashSet { item1Type1Game1X9, item3Type2Game2 }; + HashSet itemsToGive = new HashSet { item1Type1Game1, item3Type2Game2 }; + HashSet itemsToReceive = new HashSet { item2Type1Game1, item4Type2Game2 }; + + Assert.IsTrue(AcceptsTrade(inventory, itemsToGive, itemsToReceive)); + } + + [TestMethod] + public void TradingMultiGameNeutralAccept() { + Steam.Item item1Game1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 570, Steam.Item.EType.TradingCard); + Steam.Item item1Game1X2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 2, 570, Steam.Item.EType.TradingCard); + Steam.Item item2Game1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 570, Steam.Item.EType.TradingCard); + + Steam.Item item1Game2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 730, Steam.Item.EType.TradingCard); + Steam.Item item2Game2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 730, Steam.Item.EType.TradingCard); + + HashSet inventory = new HashSet { item1Game1X2, item1Game2 }; + HashSet itemsToGive = new HashSet { item1Game1, item1Game2 }; + HashSet itemsToReceive = new HashSet { item2Game1, item2Game2 }; + + Assert.IsTrue(AcceptsTrade(inventory, itemsToGive, itemsToReceive)); + } + + [TestMethod] + public void TradingSingleGameBadReject() { + Steam.Item item1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 570, Steam.Item.EType.TradingCard); + Steam.Item item2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 570, Steam.Item.EType.TradingCard); + + HashSet inventory = new HashSet { item1, item2 }; + HashSet itemsToGive = new HashSet { item1 }; + HashSet itemsToReceive = new HashSet { item2 }; + + Assert.IsFalse(AcceptsTrade(inventory, itemsToGive, itemsToReceive)); + } + + [TestMethod] + public void TradingSingleGameGoodAccept() { + Steam.Item item1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 570, Steam.Item.EType.TradingCard); + Steam.Item item1X2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 2, 570, Steam.Item.EType.TradingCard); + Steam.Item item2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 570, Steam.Item.EType.TradingCard); + + HashSet inventory = new HashSet { item1X2 }; + HashSet itemsToGive = new HashSet { item1 }; + HashSet itemsToReceive = new HashSet { item2 }; + + Assert.IsTrue(AcceptsTrade(inventory, itemsToGive, itemsToReceive)); + } + + [TestMethod] + public void TradingSingleGameMultiTypeBadReject() { + Steam.Item item1Type1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 570, Steam.Item.EType.TradingCard); + Steam.Item item1Type1X9 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 9, 570, Steam.Item.EType.TradingCard); + Steam.Item item2Type1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 570, Steam.Item.EType.TradingCard); + + Steam.Item item3Type2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 3, 1, 570, Steam.Item.EType.Emoticon); + Steam.Item item3Type2X9 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 3, 9, 570, Steam.Item.EType.Emoticon); + Steam.Item item4Type2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 4, 1, 570, Steam.Item.EType.Emoticon); + + HashSet inventory = new HashSet { item1Type1X9, item3Type2X9, item4Type2 }; + HashSet itemsToGive = new HashSet { item1Type1, item4Type2 }; + HashSet itemsToReceive = new HashSet { item2Type1, item3Type2 }; + + Assert.IsFalse(AcceptsTrade(inventory, itemsToGive, itemsToReceive)); + } + + [TestMethod] + public void TradingSingleGameMultiTypeNeutralAccept() { + Steam.Item item1Type1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 570, Steam.Item.EType.TradingCard); + Steam.Item item1Type1X9 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 9, 570, Steam.Item.EType.TradingCard); + Steam.Item item2Type1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 570, Steam.Item.EType.TradingCard); + + Steam.Item item3Type2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 3, 1, 570, Steam.Item.EType.Emoticon); + Steam.Item item4Type2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 4, 1, 570, Steam.Item.EType.Emoticon); + + HashSet inventory = new HashSet { item1Type1X9, item3Type2 }; + HashSet itemsToGive = new HashSet { item1Type1, item3Type2 }; + HashSet itemsToReceive = new HashSet { item2Type1, item4Type2 }; + + Assert.IsTrue(AcceptsTrade(inventory, itemsToGive, itemsToReceive)); + } + + [TestMethod] + public void TradingSingleGameNeutralAccept() { + Steam.Item item1 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 1, 1, 570, Steam.Item.EType.TradingCard); + Steam.Item item2 = new Steam.Item(Steam.Item.SteamAppID, Steam.Item.SteamCommunityContextID, 2, 1, 570, Steam.Item.EType.TradingCard); + + HashSet inventory = new HashSet { item1 }; + HashSet itemsToGive = new HashSet { item1 }; + HashSet itemsToReceive = new HashSet { item2 }; + + Assert.IsTrue(AcceptsTrade(inventory, itemsToGive, itemsToReceive)); + } + + private static bool AcceptsTrade(HashSet inventory, HashSet itemsToGive, HashSet itemsToReceive) { + Type trading = typeof(ArchiSteamFarm.Trading); + MethodInfo method = trading.GetMethod("IsTradeNeutralOrBetter", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); + return (bool) method.Invoke(null, new object[] { inventory, itemsToGive, itemsToReceive }); + } + } +} \ No newline at end of file diff --git a/ArchiSteamFarm.sln b/ArchiSteamFarm.sln index 79803db10..f14b7fbc9 100644 --- a/ArchiSteamFarm.sln +++ b/ArchiSteamFarm.sln @@ -1,10 +1,12 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26608.5 +VisualStudioVersion = 15.0.26621.2 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ArchiSteamFarm", "ArchiSteamFarm\ArchiSteamFarm.csproj", "{CF84911C-2C4C-4195-8AF3-ABBB6D3DE9AA}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchiSteamFarm.Tests", "ArchiSteamFarm.Tests\ArchiSteamFarm.Tests.csproj", "{91DC4C4F-3C23-4716-8CB2-BC7EAB65D759}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,8 +17,15 @@ Global {CF84911C-2C4C-4195-8AF3-ABBB6D3DE9AA}.Debug|Any CPU.Build.0 = Debug|Any CPU {CF84911C-2C4C-4195-8AF3-ABBB6D3DE9AA}.Release|Any CPU.ActiveCfg = Release|Any CPU {CF84911C-2C4C-4195-8AF3-ABBB6D3DE9AA}.Release|Any CPU.Build.0 = Release|Any CPU + {91DC4C4F-3C23-4716-8CB2-BC7EAB65D759}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {91DC4C4F-3C23-4716-8CB2-BC7EAB65D759}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91DC4C4F-3C23-4716-8CB2-BC7EAB65D759}.Release|Any CPU.ActiveCfg = Release|Any CPU + {91DC4C4F-3C23-4716-8CB2-BC7EAB65D759}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D7D54143-C857-4B76-A219-0E98C5BC4895} + EndGlobalSection EndGlobal diff --git a/ArchiSteamFarm.sln.DotSettings b/ArchiSteamFarm.sln.DotSettings index 5e7032060..8ec2e26f3 100644 --- a/ArchiSteamFarm.sln.DotSettings +++ b/ArchiSteamFarm.sln.DotSettings @@ -384,4 +384,5 @@ True True True - True \ No newline at end of file + True + 8 \ No newline at end of file diff --git a/ArchiSteamFarm/AssemblyInfo.cs b/ArchiSteamFarm/AssemblyInfo.cs new file mode 100644 index 000000000..0dbdad1c6 --- /dev/null +++ b/ArchiSteamFarm/AssemblyInfo.cs @@ -0,0 +1,27 @@ +/* + _ _ _ ____ _ _____ + / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___ + / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \ + / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | | +/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_| + + Copyright 2015-2017 Łukasz "JustArchi" Domeradzki + Contact: JustArchi@JustArchi.net + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("ArchiSteamFarm.Tests")] diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index 76872ac51..b1b645667 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -92,6 +92,12 @@ namespace ArchiSteamFarm { Steam.Item.EType.TradingCard }; + [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)] + internal readonly HashSet MatchableTypes = new HashSet { + Steam.Item.EType.FoilTradingCard, + Steam.Item.EType.TradingCard + }; + [JsonProperty(Required = Required.DisallowNull)] internal readonly CryptoHelper.ECryptoMethod PasswordFormat = CryptoHelper.ECryptoMethod.PlainText; diff --git a/ArchiSteamFarm/JSON/Steam.cs b/ArchiSteamFarm/JSON/Steam.cs index 6f905c354..9177169cb 100644 --- a/ArchiSteamFarm/JSON/Steam.cs +++ b/ArchiSteamFarm/JSON/Steam.cs @@ -486,7 +486,15 @@ namespace ArchiSteamFarm.JSON { return true; } - internal bool IsSteamCardsRequest() => ItemsToGive.All(item => (item.AppID == Item.SteamAppID) && (item.ContextID == Item.SteamCommunityContextID) && (item.Type == Item.EType.TradingCard)); + internal bool IsValidSteamItemsRequest(HashSet acceptedTypes) { + if ((acceptedTypes == null) || (acceptedTypes.Count == 0)) { + ASF.ArchiLogger.LogNullError(nameof(acceptedTypes)); + return false; + } + + bool result = ItemsToGive.All(item => (item.AppID == Item.SteamAppID) && (item.ContextID == Item.SteamCommunityContextID) && acceptedTypes.Contains(item.Type)); + return result; + } [SuppressMessage("ReSharper", "UnusedMember.Global")] internal enum ETradeOfferState : byte { diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index 0b09307a8..49c307632 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -173,7 +173,7 @@ namespace ArchiSteamFarm { return new ParseTradeResult(tradeOffer.TradeOfferID, tradeOffer.ItemsToGive.Count > 0 ? ParseTradeResult.EResult.AcceptedWithItemLose : ParseTradeResult.EResult.AcceptedWithoutItemLose); } - // Always deny trades from blacklistem steamIDs + // Always deny trades from blacklisted steamIDs if (Bot.IsBlacklistedFromTrades(tradeOffer.OtherSteamID64)) { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedPermanently); } @@ -214,8 +214,8 @@ namespace ArchiSteamFarm { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedPermanently); } - // Decline trade if we're losing anything but steam cards, or if it's non-dupes trade - if (!tradeOffer.IsSteamCardsRequest() || !tradeOffer.IsFairTypesExchange()) { + // Decline trade if it's not fair games/types exchange or if we're requested to handle any not-accepted item type + if (!tradeOffer.IsFairTypesExchange() || !tradeOffer.IsValidSteamItemsRequest(Bot.BotConfig.MatchableTypes)) { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedPermanently); } @@ -241,17 +241,35 @@ namespace ArchiSteamFarm { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.AcceptedWithItemLose); } - // Get appIDs we're interested in - HashSet appIDs = new HashSet(tradeOffer.ItemsToGive.Select(item => item.RealAppID)); + // Get appIDs/types we're interested in + HashSet appIDs = new HashSet(); + HashSet types = new HashSet(); + + foreach (Steam.Item item in tradeOffer.ItemsToGive) { + appIDs.Add(item.RealAppID); + types.Add(item.Type); + } // Now check if it's worth for us to do the trade - HashSet inventory = await Bot.ArchiWebHandler.GetMySteamInventory(false, new HashSet { Steam.Item.EType.TradingCard }, appIDs).ConfigureAwait(false); + HashSet inventory = await Bot.ArchiWebHandler.GetMySteamInventory(false, types, appIDs).ConfigureAwait(false); if ((inventory == null) || (inventory.Count == 0)) { // If we can't check our inventory when not using MatchEverything, this is a temporary failure Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsEmpty, nameof(inventory))); return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedTemporarily); } + bool accept = IsTradeNeutralOrBetter(inventory, tradeOffer.ItemsToGive, tradeOffer.ItemsToReceive); + + // Even if trade is not neutral+ for us right now, it might be in the future, unless we're bot account where we assume that inventory doesn't change + return new ParseTradeResult(tradeOffer.TradeOfferID, accept ? ParseTradeResult.EResult.AcceptedWithItemLose : (Bot.BotConfig.IsBotAccount ? ParseTradeResult.EResult.RejectedPermanently : ParseTradeResult.EResult.RejectedTemporarily)); + } + + private static bool IsTradeNeutralOrBetter(HashSet inventory, HashSet itemsToGive, HashSet itemsToReceive) { + if ((inventory == null) || (inventory.Count == 0) || (itemsToGive == null) || (itemsToGive.Count == 0) || (itemsToReceive == null) || (itemsToReceive.Count == 0)) { + ASF.ArchiLogger.LogNullError(nameof(inventory) + " || " + nameof(itemsToGive) + " || " + nameof(itemsToReceive)); + return false; + } + // Now let's create a map which maps items to their amount in our EQ // This has to be done as we might have multiple items of given ClassID with multiple amounts Dictionary itemAmounts = new Dictionary(); @@ -264,12 +282,12 @@ namespace ArchiSteamFarm { } // Calculate our value of items to give on per-game basis - Dictionary> itemAmountToGivePerGame = new Dictionary>(appIDs.Count); + Dictionary<(Steam.Item.EType Type, uint AppID), List> itemAmountToGivePerGame = new Dictionary<(Steam.Item.EType Type, uint AppID), List>(); Dictionary itemAmountsToGive = new Dictionary(itemAmounts); - foreach (Steam.Item item in tradeOffer.ItemsToGive) { - if (!itemAmountToGivePerGame.TryGetValue(item.RealAppID, out List amountsToGive)) { + foreach (Steam.Item item in itemsToGive) { + if (!itemAmountToGivePerGame.TryGetValue((item.Type, item.RealAppID), out List amountsToGive)) { amountsToGive = new List(); - itemAmountToGivePerGame[item.RealAppID] = amountsToGive; + itemAmountToGivePerGame[(item.Type, item.RealAppID)] = amountsToGive; } if (!itemAmountsToGive.TryGetValue(item.ClassID, out uint amount)) { @@ -287,12 +305,12 @@ namespace ArchiSteamFarm { } // Calculate our value of items to receive on per-game basis - Dictionary> itemAmountToReceivePerGame = new Dictionary>(appIDs.Count); + Dictionary<(Steam.Item.EType Type, uint AppID), List> itemAmountToReceivePerGame = new Dictionary<(Steam.Item.EType Type, uint AppID), List>(); Dictionary itemAmountsToReceive = new Dictionary(itemAmounts); - foreach (Steam.Item item in tradeOffer.ItemsToReceive) { - if (!itemAmountToReceivePerGame.TryGetValue(item.RealAppID, out List amountsToReceive)) { + foreach (Steam.Item item in itemsToReceive) { + if (!itemAmountToReceivePerGame.TryGetValue((item.Type, item.RealAppID), out List amountsToReceive)) { amountsToReceive = new List(); - itemAmountToReceivePerGame[item.RealAppID] = amountsToReceive; + itemAmountToReceivePerGame[(item.Type, item.RealAppID)] = amountsToReceive; } if (!itemAmountsToReceive.TryGetValue(item.ClassID, out uint amount)) { @@ -313,10 +331,7 @@ namespace ArchiSteamFarm { // This is quite complex operation of taking minimum difference from all differences on per-game basis // When calculating per-game difference, we sum only amounts at proper indexes, because user might be overpaying int difference = itemAmountToGivePerGame.Min(kv => kv.Value.Select((t, i) => (int) (t - itemAmountToReceivePerGame[kv.Key][i])).Sum()); - - // Trade is neutral+ for us if the difference is greater than 0 - // If not, we assume that the trade might be good for us in the future, unless we're bot account where we assume that inventory doesn't change - return new ParseTradeResult(tradeOffer.TradeOfferID, difference > 0 ? ParseTradeResult.EResult.AcceptedWithItemLose : (Bot.BotConfig.IsBotAccount ? ParseTradeResult.EResult.RejectedPermanently : ParseTradeResult.EResult.RejectedTemporarily)); + return difference > 0; } private sealed class ParseTradeResult { diff --git a/ArchiSteamFarm/config/example.json b/ArchiSteamFarm/config/example.json index 69f1bea62..a7c7de859 100644 --- a/ArchiSteamFarm/config/example.json +++ b/ArchiSteamFarm/config/example.json @@ -15,6 +15,10 @@ 3, 5 ], + "MatchableTypes": [ + 3, + 5 + ], "PasswordFormat": 0, "Paused": false, "RedeemingPreferences": 0,