internal Confirmation(uint id, ulong key, Steam.ConfirmationDetails.EType type) { if ((id == 0) || (key == 0) || (type == Steam.ConfirmationDetails.EType.Unknown)) { throw new ArgumentNullException(nameof(id) + " || " + nameof(key) + " || " + nameof(type)); } ID = id; Key = key; Type = type; }
public static Steam GetClient() { if(client == null) { client = new Steam(); autoReconnect = true; } return client; }
public MainWindow(Steam.Environment steamEnv) { #if !DEBUG // Show Splash in release version System.Threading.Thread.Sleep(2000); #endif InitializeComponent(); SteamEnv = steamEnv; labelAccountName.Content = "Account: " + SteamEnv.AccountName; }
private async Task<ParseTradeResult> ShouldAcceptTrade(Steam.TradeOffer tradeOffer) { if (tradeOffer == null) { Bot.ArchiLogger.LogNullError(nameof(tradeOffer)); return null; } // Always accept trades from SteamMasterID if ((tradeOffer.OtherSteamID64 != 0) && ((tradeOffer.OtherSteamID64 == Bot.BotConfig.SteamMasterID) || (tradeOffer.OtherSteamID64 == Program.GlobalConfig.SteamOwnerID))) { return new ParseTradeResult(tradeOffer.TradeOfferID, tradeOffer.ItemsToGive.Count > 0 ? ParseTradeResult.EResult.AcceptedWithItemLose : ParseTradeResult.EResult.AcceptedWithoutItemLose); } // Check if it's donation trade if (tradeOffer.ItemsToGive.Count == 0) { ParseTradeResult.EResult donationResult; // If it's steam fuckup, temporarily ignore it, otherwise react accordingly, depending on our preference if (tradeOffer.ItemsToReceive.Count == 0) { donationResult = ParseTradeResult.EResult.RejectedTemporarily; } else if (Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.AcceptDonations) || ((tradeOffer.OtherSteamID64 != 0) && Bot.Bots.Values.Any(bot => bot.SteamID == tradeOffer.OtherSteamID64))) { donationResult = ParseTradeResult.EResult.AcceptedWithoutItemLose; } else { donationResult = ParseTradeResult.EResult.RejectedPermanently; } return new ParseTradeResult(tradeOffer.TradeOfferID, donationResult); } // If we don't have SteamTradeMatcher enabled, this is the end for us if (!Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher)) { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedPermanently); } // Decline trade if we're giving more count-wise if (tradeOffer.ItemsToGive.Count > tradeOffer.ItemsToReceive.Count) { 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()) { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.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 new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.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 new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.RejectedPermanently); } } // If we're matching everything, this is enough for us if (Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything)) { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.AcceptedWithItemLose); } // Now check if it's worth for us to do the trade await LimitInventoryRequestsAsync().ConfigureAwait(false); HashSet<Steam.Item> inventory = await Bot.ArchiWebHandler.GetMySteamInventory(false).ConfigureAwait(false); if ((inventory == null) || (inventory.Count == 0)) { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.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)); // If for some reason Valve is talking crap and we can't find mentioned items, assume OK if (inventory.Count == 0) { return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.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 // 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)); }
private async Task<ParseTradeResult> ParseTrade(Steam.TradeOffer tradeOffer) { if (tradeOffer == null) { Bot.ArchiLogger.LogNullError(nameof(tradeOffer)); return null; } if (tradeOffer.State != Steam.TradeOffer.ETradeOfferState.Active) { Bot.ArchiLogger.LogGenericError("Ignoring trade in non-active state!"); return null; } ParseTradeResult result = await ShouldAcceptTrade(tradeOffer).ConfigureAwait(false); if (result == null) { Bot.ArchiLogger.LogNullError(nameof(result)); return null; } switch (result.Result) { case ParseTradeResult.EResult.AcceptedWithItemLose: case ParseTradeResult.EResult.AcceptedWithoutItemLose: Bot.ArchiLogger.LogGenericInfo("Accepting trade: " + tradeOffer.TradeOfferID); await Bot.ArchiWebHandler.AcceptTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false); break; case ParseTradeResult.EResult.RejectedPermanently: case ParseTradeResult.EResult.RejectedTemporarily: if (result.Result == ParseTradeResult.EResult.RejectedPermanently) { if (Bot.BotConfig.IsBotAccount) { Bot.ArchiLogger.LogGenericInfo("Rejecting trade: " + tradeOffer.TradeOfferID); Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID); break; } IgnoredTrades.Add(tradeOffer.TradeOfferID); } Bot.ArchiLogger.LogGenericInfo("Ignoring trade: " + tradeOffer.TradeOfferID); break; } return result; }
private async Task<ParseTradeResult> ParseTrade(Steam.TradeOffer tradeOffer) { if (tradeOffer == null) { Logging.LogNullError(nameof(tradeOffer), Bot.BotName); return ParseTradeResult.Error; } if (tradeOffer.State != Steam.TradeOffer.ETradeOfferState.Active) { return ParseTradeResult.Error; } ParseTradeResult result = await ShouldAcceptTrade(tradeOffer).ConfigureAwait(false); switch (result) { case ParseTradeResult.AcceptedWithItemLose: case ParseTradeResult.AcceptedWithoutItemLose: Logging.LogGenericInfo("Accepting trade: " + tradeOffer.TradeOfferID, Bot.BotName); return await Bot.ArchiWebHandler.AcceptTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false) ? result : ParseTradeResult.Error; case ParseTradeResult.RejectedPermanently: case ParseTradeResult.RejectedTemporarily: if (result == ParseTradeResult.RejectedPermanently) { if (Bot.BotConfig.IsBotAccount) { Logging.LogGenericInfo("Rejecting trade: " + tradeOffer.TradeOfferID, Bot.BotName); return Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID) ? result : ParseTradeResult.Error; } IgnoredTrades.Add(tradeOffer.TradeOfferID); } Logging.LogGenericInfo("Ignoring trade: " + tradeOffer.TradeOfferID, Bot.BotName); return result; default: return result; } }
public Space(Steam plugin) { this.plugin = plugin; }
private void Cleanup() { if (SteamInterface != null) { if (Application.isEditor) { // Only release managed handles if we run from inside the editor. This enables us // to use the library again without restarting the editor. SteamInterface.ReleaseManagedResources(); } else { // We are running from a standalone build. Shutdown the library completely SteamInterface.Shutdown(); } SteamInterface = null; } }
private bool ShouldAcceptTrade(Steam.TradeOffer tradeOffer) { if (tradeOffer == null) { return false; } // Always accept trades when we're not losing anything if (tradeOffer.items_to_give.Count == 0) { // Unless it's steam fuckup and we're dealing with broken trade return tradeOffer.items_to_receive.Count > 0; } // Always accept trades from SteamMasterID if (tradeOffer.OtherSteamID64 != 0 && tradeOffer.OtherSteamID64 == Bot.BotConfig.SteamMasterID) { return true; } // TODO: Add optional SteamTradeMatcher integration here // If no rule above matched this trade, reject it return false; }
private async Task ParseTrade(Steam.TradeOffer tradeOffer) { if (tradeOffer == null || tradeOffer.trade_offer_state != Steam.TradeOffer.ETradeOfferState.Active) { return; } ulong tradeID; if (!ulong.TryParse(tradeOffer.tradeofferid, out tradeID)) { return; } if (ShouldAcceptTrade(tradeOffer)) { Logging.LogGenericInfo("Accepting trade: " + tradeID, Bot.BotName); await Bot.ArchiWebHandler.AcceptTradeOffer(tradeID).ConfigureAwait(false); } else { Logging.LogGenericInfo("Ignoring trade: " + tradeID, Bot.BotName); } }
internal async Task AcceptConfirmations(bool accept, Steam.ConfirmationDetails.EType acceptedType = Steam.ConfirmationDetails.EType.Unknown, ulong acceptedSteamID = 0, HashSet<ulong> acceptedTradeIDs = null) { if (BotDatabase.MobileAuthenticator == null) { return; } HashSet<MobileAuthenticator.Confirmation> confirmations = await BotDatabase.MobileAuthenticator.GetConfirmations().ConfigureAwait(false); if ((confirmations == null) || (confirmations.Count == 0)) { return; } if (acceptedType != Steam.ConfirmationDetails.EType.Unknown) { if (confirmations.RemoveWhere(confirmation => (confirmation.Type != acceptedType) && (confirmation.Type != Steam.ConfirmationDetails.EType.Other)) > 0) { confirmations.TrimExcess(); if (confirmations.Count == 0) { return; } } } if ((acceptedSteamID != 0) || ((acceptedTradeIDs != null) && (acceptedTradeIDs.Count > 0))) { Steam.ConfirmationDetails[] detailsResults = await Task.WhenAll(confirmations.Select(BotDatabase.MobileAuthenticator.GetConfirmationDetails)).ConfigureAwait(false); HashSet<uint> ignoredConfirmationIDs = new HashSet<uint>(); foreach (Steam.ConfirmationDetails details in detailsResults.Where(details => (details != null) && ( ((acceptedSteamID != 0) && (details.OtherSteamID64 != 0) && (acceptedSteamID != details.OtherSteamID64)) || ((acceptedTradeIDs != null) && (details.TradeOfferID != 0) && !acceptedTradeIDs.Contains(details.TradeOfferID)) ))) { ignoredConfirmationIDs.Add(details.ConfirmationID); } if (ignoredConfirmationIDs.Count > 0) { if (confirmations.RemoveWhere(confirmation => ignoredConfirmationIDs.Contains(confirmation.ID)) > 0) { confirmations.TrimExcess(); if (confirmations.Count == 0) { return; } } } } // This could be done in parallel, but for some reason Steam allows only one confirmation being accepted at the time // Therefore, even though no physical barrier stops us from doing so, we execute this synchronously foreach (MobileAuthenticator.Confirmation confirmation in confirmations) { await BotDatabase.MobileAuthenticator.HandleConfirmation(confirmation, accept).ConfigureAwait(false); } }
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; }
private async Task<bool> ParseTrade(Steam.TradeOffer tradeOffer) { if (tradeOffer == null) { Logging.LogNullError(nameof(tradeOffer), Bot.BotName); return false; } if (tradeOffer.State != Steam.TradeOffer.ETradeOfferState.Active) { return false; } if (await ShouldAcceptTrade(tradeOffer).ConfigureAwait(false)) { Logging.LogGenericInfo("Accepting trade: " + tradeOffer.TradeOfferID, Bot.BotName); return await Bot.ArchiWebHandler.AcceptTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false); } if (Bot.BotConfig.IsBotAccount) { Logging.LogGenericInfo("Rejecting trade: " + tradeOffer.TradeOfferID, Bot.BotName); return Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID); } Logging.LogGenericInfo("Ignoring trade: " + tradeOffer.TradeOfferID, Bot.BotName); return false; }
public Game(Steam plugin) { this.plugin = plugin; }
private void Awake() { Steam.RestartAppIfNecessary(480); // Makes sure that only one instance of this object is in use at a time if (SteamInterface == null) { bool error = false; try { // Starts the library. This will, and can, only be done once. SteamInterface = Steam.Initialize(); } catch (AlreadyLoadedException e) { status = "The native dll is already loaded, this should not happen if ReleaseManagedResources is used and Steam.Initialize() is only called once."; Debug.LogError(status, this); Debug.LogError(e.Message, this); error = true; } catch (SteamInitializeFailedException e) { status = "Could not initialize the native Steamworks API. This is usually caused by a missing steam_appid.txt file or if the Steam client is not running."; Debug.LogError(status, this); Debug.LogError(e.Message, this); error = true; } catch (SteamInterfaceInitializeFailedException e) { status = "Could not initialize the wanted versions of the Steamworks API. Make sure that you have the correct Steamworks SDK version. See the documentation for more info."; Debug.LogError(status, this); Debug.LogError(e.Message, this); error = true; } catch (DllNotFoundException e) { status = "Could not load a dll file. Make sure that the steam_api.dll/libsteam_api.dylib file is placed at the correct location. See the documentation for more info."; Debug.LogError(status, this); Debug.LogError(e.Message, this); error = true; } if (error) { SteamInterface = null; } else { status = "Steamworks initialized and ready to use."; #if UNITY_WINDOWS if (SteamInterface.Utils.IsSteamRunningInVR()) { HmdError result; result = SteamInterface.Hmd.Init(); Debug.Log("Result: " + result); } #endif // Prevent destruction of this object GameObject.DontDestroyOnLoad(this); activeInstance = this; // An event is used to notify us about any exceptions thrown from native code. SteamInterface.ExceptionThrown += ExceptionThrown; // Listen to when the game overlay is shown or hidden SteamInterface.Friends.GameOverlayActivated += OverlayToggle; hasLicense = SteamInterface.User.UserHasLicenseForApp(SteamInterface.User.GetSteamID(), SteamInterface.AppID); } } else { // Another Steamworks object is already created, destroy this one. Destroy(this); } }
internal async Task<bool> AcceptConfirmations(bool accept, Steam.ConfirmationDetails.EType acceptedType = Steam.ConfirmationDetails.EType.Unknown, ulong acceptedSteamID = 0, HashSet<ulong> acceptedTradeIDs = null) { if (BotDatabase.MobileAuthenticator == null) { return false; } while (true) { HashSet<MobileAuthenticator.Confirmation> confirmations = await BotDatabase.MobileAuthenticator.GetConfirmations().ConfigureAwait(false); if ((confirmations == null) || (confirmations.Count == 0)) { return true; } if (acceptedType != Steam.ConfirmationDetails.EType.Unknown) { if (confirmations.RemoveWhere(confirmation => (confirmation.Type != acceptedType) && (confirmation.Type != Steam.ConfirmationDetails.EType.Other)) > 0) { if (confirmations.Count == 0) { return true; } } } if ((acceptedSteamID == 0) && ((acceptedTradeIDs == null) || (acceptedTradeIDs.Count == 0))) { if (!await BotDatabase.MobileAuthenticator.HandleConfirmations(confirmations, accept).ConfigureAwait(false)) { return false; } continue; } Steam.ConfirmationDetails[] detailsResults = await Task.WhenAll(confirmations.Select(BotDatabase.MobileAuthenticator.GetConfirmationDetails)).ConfigureAwait(false); HashSet<MobileAuthenticator.Confirmation> ignoredConfirmations = new HashSet<MobileAuthenticator.Confirmation>(detailsResults.Where(details => (details != null) && ( ((acceptedSteamID != 0) && (details.OtherSteamID64 != 0) && (acceptedSteamID != details.OtherSteamID64)) || ((acceptedTradeIDs != null) && (details.TradeOfferID != 0) && !acceptedTradeIDs.Contains(details.TradeOfferID)) )).Select(details => details.Confirmation)); if (ignoredConfirmations.Count > 0) { confirmations.ExceptWith(ignoredConfirmations); if (confirmations.Count == 0) { return true; } } if (!await BotDatabase.MobileAuthenticator.HandleConfirmations(confirmations, accept).ConfigureAwait(false)) { return false; } } }
private void firstUpdate() { var current = 0; var files = Directory.GetFiles(Program.GeometryDashPath + @"\Resources"); SizeText.Text = @"0 of " + (necessaryFiles.Length + files.Length) + @" files"; foreach (string file in files) { var fileName = Path.GetFileName(file); var destFile = Path.Combine(Program.HyperfluxResourcesPath, fileName); File.Copy(file, destFile, true); UpdateContents(fileName); } foreach (var filename in necessaryFiles) { var file = Path.Combine(Steam.AppDir(322170), filename); var fileName = Path.GetFileName(file); var destFile = Path.Combine(Program.HyperfluxPath, fileName); File.Copy(file, destFile, true); UpdateContents(fileName); } // mine void ResetContents() { FileName.Text = @"Downloading: ???"; ProgressBar.Value = 0; SizeText.Update(); FileName.Update(); } void UpdateContents(string fileName) { current++; var progress = (int)((float)current / (necessaryFiles.Length + files.Length) * 100); FileName.Text = @"Copying: " + fileName; SizeText.Text = current + @" of " + (necessaryFiles.Length + files.Length) + @" files"; ProgressBar.Value = progress; SizeText.Update(); FileName.Update(); if (progress == 100) { ResetContents(); RunUpdate(); } } }