Example #1
0
		private async Task<ParseTradeResult> ShouldAcceptTrade(Steam.TradeOffer tradeOffer) {
			if (tradeOffer == null) {
				Logging.LogNullError(nameof(tradeOffer), Bot.BotName);
				return ParseTradeResult.Error;
			}

			// Always accept trades when we're not losing anything
			if (tradeOffer.ItemsToGive.Count == 0) {
				// Unless it's steam fuckup and we're dealing with broken trade
				return tradeOffer.ItemsToReceive.Count > 0 ? ParseTradeResult.AcceptedWithoutItemLose : ParseTradeResult.RejectedTemporarily;
			}

			// Always accept trades from SteamMasterID
			if ((tradeOffer.OtherSteamID64 != 0) && (tradeOffer.OtherSteamID64 == Bot.BotConfig.SteamMasterID)) {
				return ParseTradeResult.AcceptedWithItemLose;
			}

			// If we don't have SteamTradeMatcher enabled, this is the end for us
			if (!Bot.BotConfig.SteamTradeMatcher) {
				return ParseTradeResult.RejectedPermanently;
			}

			// Decline trade if we're giving more count-wise
			if (tradeOffer.ItemsToGive.Count > tradeOffer.ItemsToReceive.Count) {
				return ParseTradeResult.RejectedPermanently;
			}

			// Decline trade if we're losing anything but steam cards, or if it's non-dupes trade
			if (!tradeOffer.IsSteamCardsOnlyTradeForUs() || !tradeOffer.IsPotentiallyDupesTradeForUs()) {
				return ParseTradeResult.RejectedPermanently;
			}

			// At this point we're sure that STM trade is valid

			// Fetch trade hold duration
			byte? holdDuration = await Bot.ArchiWebHandler.GetTradeHoldDuration(tradeOffer.TradeOfferID).ConfigureAwait(false);
			if (!holdDuration.HasValue) {
				// If we can't get trade hold duration, reject trade temporarily
				return ParseTradeResult.RejectedTemporarily;
			}

			// If user has a trade hold, we add extra logic
			if (holdDuration.Value > 0) {
				// If trade hold duration exceeds our max, or user asks for cards with short lifespan, reject the trade
				if ((holdDuration.Value > Program.GlobalConfig.MaxTradeHoldDuration) || tradeOffer.ItemsToGive.Any(item => GlobalConfig.GlobalBlacklist.Contains(item.RealAppID))) {
					return ParseTradeResult.RejectedPermanently;
				}
			}

			// Now check if it's worth for us to do the trade
			await LimitInventoryRequestsAsync().ConfigureAwait(false);

			HashSet<Steam.Item> inventory = await Bot.ArchiWebHandler.GetMyInventory(false).ConfigureAwait(false);
			if ((inventory == null) || (inventory.Count == 0)) {
				return ParseTradeResult.AcceptedWithItemLose; // OK, assume that this trade is valid, we can't check our EQ
			}

			// Get appIDs we're interested in
			HashSet<uint> appIDs = new HashSet<uint>(tradeOffer.ItemsToGive.Select(item => item.RealAppID));

			// Now remove from our inventory all items we're NOT interested in
			inventory.RemoveWhere(item => !appIDs.Contains(item.RealAppID));
			inventory.TrimExcess();

			// If for some reason Valve is talking crap and we can't find mentioned items, assume OK
			if (inventory.Count == 0) {
				return ParseTradeResult.AcceptedWithItemLose;
			}

			// Now let's create a map which maps items to their amount in our EQ
			Dictionary<ulong, uint> amountMap = new Dictionary<ulong, uint>();
			foreach (Steam.Item item in inventory) {
				uint amount;
				if (amountMap.TryGetValue(item.ClassID, out amount)) {
					amountMap[item.ClassID] = amount + item.Amount;
				} else {
					amountMap[item.ClassID] = item.Amount;
				}
			}

			// Calculate our value of items to give
			List<uint> amountsToGive = new List<uint>(tradeOffer.ItemsToGive.Count);
			Dictionary<ulong, uint> amountMapToGive = new Dictionary<ulong, uint>(amountMap);
			foreach (ulong key in tradeOffer.ItemsToGive.Select(item => item.ClassID)) {
				uint amount;
				if (!amountMapToGive.TryGetValue(key, out amount)) {
					amountsToGive.Add(0);
					continue;
				}

				amountsToGive.Add(amount);
				amountMapToGive[key] = amount - 1; // We're giving one, so we have one less
			}

			// Sort it ascending
			amountsToGive.Sort();

			// Calculate our value of items to receive
			List<uint> amountsToReceive = new List<uint>(tradeOffer.ItemsToReceive.Count);
			Dictionary<ulong, uint> amountMapToReceive = new Dictionary<ulong, uint>(amountMap);
			foreach (ulong key in tradeOffer.ItemsToReceive.Select(item => item.ClassID)) {
				uint amount;
				if (!amountMapToReceive.TryGetValue(key, out amount)) {
					amountsToReceive.Add(0);
					continue;
				}

				amountsToReceive.Add(amount);
				amountMapToReceive[key] = amount + 1; // We're getting one, so we have one more
			}

			// Sort it ascending
			amountsToReceive.Sort();

			// Check actual difference
			// We sum only values at proper indexes of giving, because user might be overpaying
			int difference = amountsToGive.Select((t, i) => (int) (t - amountsToReceive[i])).Sum();

			// Trade is worth for us if the difference is greater than 0
			return difference > 0 ? ParseTradeResult.AcceptedWithItemLose : ParseTradeResult.RejectedTemporarily;
		}
Example #2
0
		private async Task<bool> ShouldAcceptTrade(Steam.TradeOffer tradeOffer) {
			if (tradeOffer == null) {
				Logging.LogNullError(nameof(tradeOffer), Bot.BotName);
				return false;
			}

			// Always accept trades when we're not losing anything
			if (tradeOffer.ItemsToGive.Count == 0) {
				// Unless it's steam fuckup and we're dealing with broken trade
				return tradeOffer.ItemsToReceive.Count > 0;
			}

			// Always accept trades from SteamMasterID
			if ((tradeOffer.OtherSteamID64 != 0) && (tradeOffer.OtherSteamID64 == Bot.BotConfig.SteamMasterID)) {
				return true;
			}

			// If we don't have SteamTradeMatcher enabled, this is the end for us
			if (!Bot.BotConfig.SteamTradeMatcher) {
				return false;
			}

			// Decline trade if we're giving more count-wise
			if (tradeOffer.ItemsToGive.Count > tradeOffer.ItemsToReceive.Count) {
				return false;
			}

			// Decline trade if we're losing anything but steam cards, or if it's non-dupes trade
			if (!tradeOffer.IsSteamCardsOnlyTradeForUs() || !tradeOffer.IsPotentiallyDupesTradeForUs()) {
				return false;
			}

			// At this point we're sure that STM trade is valid

			// If we're dealing with special cards with short lifespan, accept the trade only if user doesn't have trade holds
			if (tradeOffer.ItemsToGive.Any(item => GlobalConfig.GlobalBlacklist.Contains(item.RealAppID))) {
				byte? holdDuration = await Bot.ArchiWebHandler.GetTradeHoldDuration(tradeOffer.TradeOfferID).ConfigureAwait(false);
				if (holdDuration.GetValueOrDefault() > 0) {
					return false;
				}
			}

			// Now check if it's worth for us to do the trade
			await LimitInventoryRequestsAsync().ConfigureAwait(false);

			HashSet<Steam.Item> inventory = await Bot.ArchiWebHandler.GetMyInventory(false).ConfigureAwait(false);
			if ((inventory == null) || (inventory.Count == 0)) {
				return true; // OK, assume that this trade is valid, we can't check our EQ
			}

			// Get appIDs we're interested in
			HashSet<uint> appIDs = new HashSet<uint>(tradeOffer.ItemsToGive.Select(item => item.RealAppID));

			// Now remove from our inventory all items we're NOT interested in
			inventory.RemoveWhere(item => !appIDs.Contains(item.RealAppID));
			inventory.TrimExcess();

			// If for some reason Valve is talking crap and we can't find mentioned items, assume OK
			if (inventory.Count == 0) {
				return true;
			}

			// Now let's create a map which maps items to their amount in our EQ
			Dictionary<ulong, uint> amountMap = new Dictionary<ulong, uint>();
			foreach (Steam.Item item in inventory) {
				uint amount;
				if (amountMap.TryGetValue(item.ClassID, out amount)) {
					amountMap[item.ClassID] = amount + item.Amount;
				} else {
					amountMap[item.ClassID] = item.Amount;
				}
			}

			// Calculate our value of items to give
			List<uint> amountsToGive = new List<uint>(tradeOffer.ItemsToGive.Count);
			foreach (ulong key in tradeOffer.ItemsToGive.Select(item => item.ClassID)) {
				uint amount;
				if (!amountMap.TryGetValue(key, out amount)) {
					amountsToGive.Add(0);
					continue;
				}

				amountsToGive.Add(amount);
			}

			// Sort it ascending
			amountsToGive.Sort();

			// Calculate our value of items to receive
			List<uint> amountsToReceive = new List<uint>(tradeOffer.ItemsToReceive.Count);
			foreach (ulong key in tradeOffer.ItemsToReceive.Select(item => item.ClassID)) {
				uint amount;
				if (!amountMap.TryGetValue(key, out amount)) {
					amountsToReceive.Add(0);
					continue;
				}

				amountsToReceive.Add(amount);
			}

			// Sort it ascending
			amountsToReceive.Sort();

			// Check actual difference
			int difference = amountsToGive.Select((t, i) => (int) (t - amountsToReceive[i])).Sum();

			// Trade is worth for us if the difference is greater than 0
			return difference > 0;
		}