diff --git a/ArchiSteamFarm/ASF-ConfigGenerator.exe b/ArchiSteamFarm/ASF-ConfigGenerator.exe new file mode 100644 index 000000000..36385bb5c Binary files /dev/null and b/ArchiSteamFarm/ASF-ConfigGenerator.exe differ diff --git a/ArchiSteamFarm/ArchiHandler.cs b/ArchiSteamFarm/ArchiHandler.cs index 4d5dc3cd7..9918b1795 100644 --- a/ArchiSteamFarm/ArchiHandler.cs +++ b/ArchiSteamFarm/ArchiHandler.cs @@ -26,7 +26,9 @@ using SteamKit2; using SteamKit2.Internal; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Linq; using System.Net; using System.Threading.Tasks; @@ -36,7 +38,7 @@ namespace ArchiSteamFarm { internal ArchiHandler(Bot bot) { if (bot == null) { - throw new ArgumentNullException("bot"); + throw new ArgumentNullException(nameof(bot)); } Bot = bot; @@ -53,6 +55,7 @@ namespace ArchiSteamFarm { internal sealed class NotificationsCallback : CallbackMsg { internal enum ENotification : byte { + [SuppressMessage("ReSharper", "UnusedMember.Global")] Unknown = 0, Trading = 1, // Only custom below, different than ones available as user_notification_type @@ -62,21 +65,21 @@ namespace ArchiSteamFarm { internal readonly HashSet Notifications; internal NotificationsCallback(JobID jobID, CMsgClientUserNotifications msg) { - if (jobID == null || msg == null) { - throw new ArgumentNullException("jobID || msg"); + if ((jobID == null) || (msg == null)) { + throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } JobID = jobID; Notifications = new HashSet(); - foreach (var notification in msg.notifications) { + foreach (CMsgClientUserNotifications.Notification notification in msg.notifications) { Notifications.Add((ENotification) notification.user_notification_type); } } internal NotificationsCallback(JobID jobID, CMsgClientItemAnnouncements msg) { - if (jobID == null || msg == null) { - throw new ArgumentNullException("jobID || msg"); + if ((jobID == null) || (msg == null)) { + throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } JobID = jobID; @@ -93,8 +96,8 @@ namespace ArchiSteamFarm { internal readonly uint OfflineMessagesCount; internal OfflineMessageCallback(JobID jobID, CMsgClientOfflineMessageNotification msg) { - if (jobID == null || msg == null) { - throw new ArgumentNullException("jobID || msg"); + if ((jobID == null) || (msg == null)) { + throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } JobID = jobID; @@ -104,6 +107,7 @@ namespace ArchiSteamFarm { internal sealed class PurchaseResponseCallback : CallbackMsg { internal enum EPurchaseResult : sbyte { + [SuppressMessage("ReSharper", "UnusedMember.Global")] Unknown = -1, OK = 0, AlreadyOwned = 9, @@ -114,31 +118,28 @@ namespace ArchiSteamFarm { OnCooldown = 53 } - internal readonly EResult Result; internal readonly EPurchaseResult PurchaseResult; - internal readonly KeyValue ReceiptInfo; internal readonly Dictionary Items; internal PurchaseResponseCallback(JobID jobID, CMsgClientPurchaseResponse msg) { - if (jobID == null || msg == null) { - throw new ArgumentNullException("jobID || msg"); + if ((jobID == null) || (msg == null)) { + throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); } JobID = jobID; - Result = (EResult) msg.eresult; PurchaseResult = (EPurchaseResult) msg.purchase_result_details; if (msg.purchase_receipt_info == null) { return; } - ReceiptInfo = new KeyValue(); + KeyValue receiptInfo = new KeyValue(); using (MemoryStream ms = new MemoryStream(msg.purchase_receipt_info)) { - if (!ReceiptInfo.TryReadAsBinary(ms)) { + if (!receiptInfo.TryReadAsBinary(ms)) { return; } - var lineItems = ReceiptInfo["lineitems"].Children; + List lineItems = receiptInfo["lineitems"].Children; Items = new Dictionary(lineItems.Count); foreach (KeyValue lineItem in lineItems) { @@ -165,11 +166,11 @@ namespace ArchiSteamFarm { return; } - var request = new ClientMsgProtobuf(EMsg.ClientGamesPlayed); + ClientMsgProtobuf request = new ClientMsgProtobuf(EMsg.ClientGamesPlayed); if (!string.IsNullOrEmpty(gameName)) { request.Body.games_played.Add(new CMsgClientGamesPlayed.GamePlayed { game_extra_info = gameName, - game_id = new GameID() { + game_id = new GameID { AppType = GameID.GameType.Shortcut, ModID = uint.MaxValue } @@ -188,18 +189,14 @@ namespace ArchiSteamFarm { } internal void PlayGames(HashSet gameIDs) { - if (gameIDs == null || !Client.IsConnected) { + if ((gameIDs == null) || !Client.IsConnected) { return; } - var request = new ClientMsgProtobuf(EMsg.ClientGamesPlayed); - foreach (uint gameID in gameIDs) { - if (gameID == 0) { - continue; - } - + ClientMsgProtobuf request = new ClientMsgProtobuf(EMsg.ClientGamesPlayed); + foreach (uint gameID in gameIDs.Where(gameID => gameID != 0)) { request.Body.games_played.Add(new CMsgClientGamesPlayed.GamePlayed { - game_id = new GameID(gameID), + game_id = new GameID(gameID) }); } @@ -211,7 +208,7 @@ namespace ArchiSteamFarm { return null; } - var request = new ClientMsgProtobuf(EMsg.ClientRegisterKey) { + ClientMsgProtobuf request = new ClientMsgProtobuf(EMsg.ClientRegisterKey) { SourceJobID = Client.GetNextJobID() }; @@ -235,8 +232,11 @@ namespace ArchiSteamFarm { SteamID steamID = new SteamID(details.AccountID, details.AccountInstance, Client.ConnectedUniverse, EAccountType.Individual); - var logon = new ClientMsgProtobuf(EMsg.ClientLogon); - logon.Body.obfustucated_private_ip = details.LoginID.Value; + ClientMsgProtobuf logon = new ClientMsgProtobuf(EMsg.ClientLogon); + if (details.LoginID != null) { + logon.Body.obfustucated_private_ip = details.LoginID.Value; + } + logon.ProtoHeader.client_sessionid = 0; logon.ProtoHeader.steamid = steamID.ConvertToUInt64(); logon.Body.account_name = details.Username; @@ -292,7 +292,7 @@ namespace ArchiSteamFarm { return; } - var response = new ClientMsgProtobuf(packetMsg); + ClientMsgProtobuf response = new ClientMsgProtobuf(packetMsg); Client.PostCallback(new OfflineMessageCallback(packetMsg.TargetJobID, response.Body)); } @@ -301,7 +301,7 @@ namespace ArchiSteamFarm { return; } - var response = new ClientMsgProtobuf(packetMsg); + ClientMsgProtobuf response = new ClientMsgProtobuf(packetMsg); Client.PostCallback(new NotificationsCallback(packetMsg.TargetJobID, response.Body)); } @@ -310,7 +310,7 @@ namespace ArchiSteamFarm { return; } - var response = new ClientMsgProtobuf(packetMsg); + ClientMsgProtobuf response = new ClientMsgProtobuf(packetMsg); Client.PostCallback(new PurchaseResponseCallback(packetMsg.TargetJobID, response.Body)); } @@ -319,7 +319,7 @@ namespace ArchiSteamFarm { return; } - var response = new ClientMsgProtobuf(packetMsg); + ClientMsgProtobuf response = new ClientMsgProtobuf(packetMsg); Client.PostCallback(new NotificationsCallback(packetMsg.TargetJobID, response.Body)); } } diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index ee124749b..841f5118e 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -32,6 +32,7 @@ using System.Text; using System.Threading.Tasks; using System.Xml; using System.Threading; +using ArchiSteamFarm.JSON; namespace ArchiSteamFarm { internal sealed class ArchiWebHandler { @@ -63,11 +64,7 @@ namespace ArchiSteamFarm { } uint appID; - if (!uint.TryParse(hashName.Substring(0, index), out appID)) { - return 0; - } - - return appID; + return !uint.TryParse(hashName.Substring(0, index), out appID) ? 0 : appID; } private static Steam.Item.EType GetItemType(string name) { @@ -87,21 +84,23 @@ namespace ArchiSteamFarm { default: if (name.EndsWith("Emoticon", StringComparison.Ordinal)) { return Steam.Item.EType.Emoticon; - } else if (name.EndsWith("Foil Trading Card", StringComparison.Ordinal)) { - return Steam.Item.EType.FoilTradingCard; - } else if (name.EndsWith("Profile Background", StringComparison.Ordinal)) { - return Steam.Item.EType.ProfileBackground; - } else if (name.EndsWith("Trading Card", StringComparison.Ordinal)) { - return Steam.Item.EType.TradingCard; - } else { - return Steam.Item.EType.Unknown; } + + if (name.EndsWith("Foil Trading Card", StringComparison.Ordinal)) { + return Steam.Item.EType.FoilTradingCard; + } + + if (name.EndsWith("Profile Background", StringComparison.Ordinal)) { + return Steam.Item.EType.ProfileBackground; + } + + return name.EndsWith("Trading Card", StringComparison.Ordinal) ? Steam.Item.EType.TradingCard : Steam.Item.EType.Unknown; } } internal ArchiWebHandler(Bot bot) { if (bot == null) { - throw new ArgumentNullException("bot"); + throw new ArgumentNullException(nameof(bot)); } Bot = bot; @@ -110,11 +109,14 @@ namespace ArchiSteamFarm { } internal bool Init(SteamClient steamClient, string webAPIUserNonce, string parentalPin) { - if (steamClient == null || steamClient.SteamID == null || string.IsNullOrEmpty(webAPIUserNonce)) { + if ((steamClient == null) || string.IsNullOrEmpty(webAPIUserNonce)) { return false; } ulong steamID = steamClient.SteamID; + if (steamID == 0) { + return false; + } string sessionID = Convert.ToBase64String(Encoding.UTF8.GetBytes(steamID.ToString())); @@ -198,16 +200,16 @@ namespace ArchiSteamFarm { }; bool result = false; - for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && !result; i++) { result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false); } - if (!result) { - Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); - return false; + if (result) { + return true; } - return true; + Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); + return false; } internal async Task JoinGroup(ulong groupID) { @@ -232,16 +234,16 @@ namespace ArchiSteamFarm { }; bool result = false; - for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && !result; i++) { result = await WebBrowser.UrlPost(request, data).ConfigureAwait(false); } - if (!result) { - Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); - return false; + if (result) { + return true; } - return true; + Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); + return false; } internal async Task> GetOwnedGames() { @@ -252,7 +254,7 @@ namespace ArchiSteamFarm { string request = SteamCommunityURL + "/my/games/?xml=1"; XmlDocument response = null; - for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && (response == null); i++) { response = await WebBrowser.UrlGetToXML(request).ConfigureAwait(false); } @@ -262,7 +264,7 @@ namespace ArchiSteamFarm { } XmlNodeList xmlNodeList = response.SelectNodes("gamesList/games/game"); - if (xmlNodeList == null || xmlNodeList.Count == 0) { + if ((xmlNodeList == null) || (xmlNodeList.Count == 0)) { return null; } @@ -290,7 +292,7 @@ namespace ArchiSteamFarm { } internal Dictionary GetOwnedGames(ulong steamID) { - if (steamID == 0 || string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) { + if ((steamID == 0) || string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) { return null; } @@ -298,7 +300,7 @@ namespace ArchiSteamFarm { using (dynamic iPlayerService = WebAPI.GetInterface("IPlayerService", Bot.BotConfig.SteamApiKey)) { iPlayerService.Timeout = Timeout; - for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && (response == null); i++) { try { response = iPlayerService.GetOwnedGames( steamid: steamID, @@ -338,7 +340,7 @@ namespace ArchiSteamFarm { using (dynamic iEconService = WebAPI.GetInterface("IEconService", Bot.BotConfig.SteamApiKey)) { iEconService.Timeout = Timeout; - for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && (response == null); i++) { try { response = iEconService.GetTradeOffers( get_received_offers: 1, @@ -389,7 +391,6 @@ namespace ArchiSteamFarm { HashSet result = new HashSet(); foreach (KeyValue trade in response["trade_offers_received"].Children) { - // TODO: Correct some of these when SK2 with https://github.com/SteamRE/SteamKit/pull/255 gets released Steam.TradeOffer tradeOffer = new Steam.TradeOffer { TradeOfferID = trade["tradeofferid"].AsUnsignedLong(), OtherSteamID3 = (uint) trade["accountid_other"].AsUnsignedLong(), @@ -468,16 +469,16 @@ namespace ArchiSteamFarm { }; bool result = false; - for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && !result; i++) { result = await WebBrowser.UrlPost(request, data, referer).ConfigureAwait(false); } - if (!result) { - Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); - return false; + if (result) { + return true; } - return true; + Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); + return false; } internal async Task> GetMyTradableInventory() { @@ -492,7 +493,7 @@ namespace ArchiSteamFarm { string request = SteamCommunityURL + "/my/inventory/json/" + Steam.Item.SteamAppID + "/" + Steam.Item.SteamContextID + "?trading=1&start=" + nextPage; JObject jObject = null; - for (byte i = 0; i < WebBrowser.MaxRetries && jObject == null; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && (jObject == null); i++) { jObject = await WebBrowser.UrlGetToJObject(request).ConfigureAwait(false); } @@ -514,7 +515,7 @@ namespace ArchiSteamFarm { } ulong classID; - if (!ulong.TryParse(classIDString, out classID) || classID == 0) { + if (!ulong.TryParse(classIDString, out classID) || (classID == 0)) { continue; } @@ -550,7 +551,7 @@ namespace ArchiSteamFarm { } IEnumerable items = jObject.SelectTokens("$.rgInventory.*"); - if (descriptions == null) { + if (items == null) { return null; } @@ -594,7 +595,7 @@ namespace ArchiSteamFarm { } internal async Task SendTradeOffer(HashSet inventory, ulong partnerID, string token = null) { - if (inventory == null || inventory.Count == 0 || partnerID == 0) { + if ((inventory == null) || (inventory.Count == 0) || (partnerID == 0)) { return false; } @@ -608,13 +609,12 @@ namespace ArchiSteamFarm { return false; } - HashSet trades = new HashSet(); - - Steam.TradeOfferRequest singleTrade = null; + Steam.TradeOfferRequest singleTrade = new Steam.TradeOfferRequest(); + HashSet trades = new HashSet { singleTrade }; byte itemID = 0; foreach (Steam.Item item in inventory) { - if (itemID % Trading.MaxItemsPerTrade == 0) { + if (itemID >= Trading.MaxItemsPerTrade) { if (trades.Count >= Trading.MaxTradesPerAccount) { break; } @@ -624,7 +624,7 @@ namespace ArchiSteamFarm { itemID = 0; } - singleTrade.ItemsToGive.Assets.Add(new Steam.Item() { + singleTrade.ItemsToGive.Assets.Add(new Steam.Item { AppID = Steam.Item.SteamAppID, ContextID = Steam.Item.SteamContextID, Amount = item.Amount, @@ -647,14 +647,16 @@ namespace ArchiSteamFarm { }; bool result = false; - for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && !result; i++) { result = await WebBrowser.UrlPost(request, data, referer).ConfigureAwait(false); } - if (!result) { - Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); - return false; + if (result) { + continue; } + + Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); + return false; } return true; @@ -672,16 +674,16 @@ namespace ArchiSteamFarm { string request = SteamCommunityURL + "/my/badges?p=" + page; HtmlDocument htmlDocument = null; - for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && (htmlDocument == null); i++) { htmlDocument = await WebBrowser.UrlGetToHtmlDocument(request).ConfigureAwait(false); } - if (htmlDocument == null) { - Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); - return null; + if (htmlDocument != null) { + return htmlDocument; } - return htmlDocument; + Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); + return null; } internal async Task GetGameCardsPage(ulong appID) { @@ -696,16 +698,16 @@ namespace ArchiSteamFarm { string request = SteamCommunityURL + "/my/gamecards/" + appID; HtmlDocument htmlDocument = null; - for (byte i = 0; i < WebBrowser.MaxRetries && htmlDocument == null; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && (htmlDocument == null); i++) { htmlDocument = await WebBrowser.UrlGetToHtmlDocument(request).ConfigureAwait(false); } - if (htmlDocument == null) { - Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); - return null; + if (htmlDocument != null) { + return htmlDocument; } - return htmlDocument; + Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); + return null; } internal async Task MarkInventory() { @@ -716,32 +718,32 @@ namespace ArchiSteamFarm { string request = SteamCommunityURL + "/my/inventory"; bool result = false; - for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && !result; i++) { result = await WebBrowser.UrlHead(request).ConfigureAwait(false); } - if (!result) { - Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); - return false; + if (result) { + return true; } - return true; + Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); + return false; } private async Task IsLoggedIn() { string request = SteamCommunityURL + "/my/profile"; Uri uri = null; - for (byte i = 0; i < WebBrowser.MaxRetries && uri == null; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && (uri == null); i++) { uri = await WebBrowser.UrlHeadToUri(request).ConfigureAwait(false); } - if (uri == null) { - Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); - return null; + if (uri != null) { + return !uri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal); } - return !uri.AbsolutePath.StartsWith("/login", StringComparison.Ordinal); + Logging.LogGenericWTF("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName); + return null; } private async Task RefreshSessionIfNeeded() { @@ -784,7 +786,7 @@ namespace ArchiSteamFarm { }; bool result = false; - for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && !result; i++) { result = await WebBrowser.UrlPost(request, data, SteamCommunityURL).ConfigureAwait(false); } diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 4de489ef4..33054b5c8 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -29,11 +29,13 @@ using SteamKit2.Internal; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; using System.Text; using System.Text.RegularExpressions; +using ArchiSteamFarm.JSON; namespace ArchiSteamFarm { internal sealed class Bot { @@ -50,17 +52,17 @@ namespace ArchiSteamFarm { internal readonly ArchiHandler ArchiHandler; internal readonly ArchiWebHandler ArchiWebHandler; internal readonly BotConfig BotConfig; - internal readonly BotDatabase BotDatabase; internal readonly SteamClient SteamClient; private readonly string SentryFile; - private readonly Timer AcceptConfirmationsTimer; - private readonly Timer SendItemsTimer; + private readonly BotDatabase BotDatabase; private readonly CallbackManager CallbackManager; private readonly CardsFarmer CardsFarmer; private readonly SteamApps SteamApps; private readonly SteamFriends SteamFriends; private readonly SteamUser SteamUser; + private readonly Timer AcceptConfirmationsTimer; + private readonly Timer SendItemsTimer; private readonly Trading Trading; internal bool KeepRunning { get; private set; } @@ -70,7 +72,7 @@ namespace ArchiSteamFarm { internal static async Task RefreshCMs(uint cellID) { bool initialized = false; - for (byte i = 0; i < WebBrowser.MaxRetries && !initialized; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && !initialized; i++) { try { Logging.LogGenericInfo("Refreshing list of CMs..."); await SteamDirectory.Initialize(cellID).ConfigureAwait(false); @@ -96,15 +98,7 @@ namespace ArchiSteamFarm { return steamID == Program.GlobalConfig.SteamOwnerID; } - private static bool IsValidCdKey(string key) { - if (string.IsNullOrEmpty(key)) { - return false; - } - - // Steam keys are offered in many formats: https://support.steampowered.com/kb_article.php?ref=7480-WUSF-3601 - // This regex should catch all of them, we can always further extend it in future - return Regex.IsMatch(key, @"[0-9A-Z]{4,5}-[0-9A-Z]{4,5}-[0-9A-Z]{4,5}-?(?:(?:[0-9A-Z]{4,5}-?)?(?:[0-9A-Z]{4,5}))?"); - } + private static bool IsValidCdKey(string key) => !string.IsNullOrEmpty(key) && Regex.IsMatch(key, @"[0-9A-Z]{4,5}-[0-9A-Z]{4,5}-[0-9A-Z]{4,5}-?(?:(?:[0-9A-Z]{4,5}-?)?(?:[0-9A-Z]{4,5}))?"); private static async Task LimitLoginRequestsAsync() { await LoginSemaphore.WaitAsync().ConfigureAwait(false); @@ -116,7 +110,7 @@ namespace ArchiSteamFarm { internal Bot(string botName) { if (string.IsNullOrEmpty(botName)) { - throw new ArgumentNullException("botName"); + throw new ArgumentNullException(nameof(botName)); } BotName = botName; @@ -203,7 +197,7 @@ namespace ArchiSteamFarm { CardsFarmer = new CardsFarmer(this); Trading = new Trading(this); - if (AcceptConfirmationsTimer == null && BotConfig.AcceptConfirmationsPeriod > 0) { + if ((AcceptConfirmationsTimer == null) && (BotConfig.AcceptConfirmationsPeriod > 0)) { AcceptConfirmationsTimer = new Timer( async e => await AcceptConfirmations(true).ConfigureAwait(false), null, @@ -212,7 +206,7 @@ namespace ArchiSteamFarm { ); } - if (SendItemsTimer == null && BotConfig.SendTradePeriod > 0) { + if ((SendItemsTimer == null) && (BotConfig.SendTradePeriod > 0)) { SendItemsTimer = new Timer( async e => await ResponseSendTrade(BotConfig.SteamMasterID).ConfigureAwait(false), null, @@ -235,7 +229,7 @@ namespace ArchiSteamFarm { } bool result = false; - for (byte i = 0; i < WebBrowser.MaxRetries && !result; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && !result; i++) { result = true; try { @@ -249,38 +243,37 @@ namespace ArchiSteamFarm { return true; } - foreach (Confirmation confirmation in confirmations) { - if (allowedConfirmationType != Confirmation.ConfirmationType.Unknown && confirmation.ConfType != allowedConfirmationType) { + foreach (Confirmation confirmation in confirmations.Where(confirmation => (allowedConfirmationType == Confirmation.ConfirmationType.Unknown) || (confirmation.ConfType == allowedConfirmationType))) { + if (confirm) { + if (BotDatabase.SteamGuardAccount.AcceptConfirmation(confirmation)) { + continue; + } + + result = false; + break; + } + + if (BotDatabase.SteamGuardAccount.DenyConfirmation(confirmation)) { continue; } - if (confirm) { - if (!BotDatabase.SteamGuardAccount.AcceptConfirmation(confirmation)) { - result = false; - break; - } - } else { - if (!BotDatabase.SteamGuardAccount.DenyConfirmation(confirmation)) { - result = false; - break; - } - } + result = false; + break; } } catch (SteamGuardAccount.WGTokenInvalidException) { result = false; - continue; } catch (Exception e) { Logging.LogGenericException(e, BotName); return false; } } - if (!result) { - Logging.LogGenericWTF("Could not accept confirmations even after " + WebBrowser.MaxRetries + " tries", BotName); - return false; + if (result) { + return true; } - return true; + Logging.LogGenericWTF("Could not accept confirmations even after " + WebBrowser.MaxRetries + " tries", BotName); + return false; } internal void ResetGamesPlayed() { @@ -306,17 +299,17 @@ namespace ArchiSteamFarm { return false; } - if (callback == null || callback.Result != EResult.OK || string.IsNullOrEmpty(callback.Nonce)) { + if ((callback == null) || (callback.Result != EResult.OK) || string.IsNullOrEmpty(callback.Nonce)) { Start().Forget(); return false; } - if (!ArchiWebHandler.Init(SteamClient, callback.Nonce, BotConfig.SteamParentalPIN)) { - Start().Forget(); - return false; + if (ArchiWebHandler.Init(SteamClient, callback.Nonce, BotConfig.SteamParentalPIN)) { + return true; } - return true; + Start().Forget(); + return false; } internal async Task OnFarmingFinished(bool farmedSomething) { @@ -331,7 +324,7 @@ namespace ArchiSteamFarm { } internal async Task Response(ulong steamID, string message) { - if (steamID == 0 || string.IsNullOrEmpty(message)) { + if ((steamID == 0) || string.IsNullOrEmpty(message)) { return null; } @@ -374,56 +367,56 @@ namespace ArchiSteamFarm { default: return ResponseUnknown(steamID); } - } else { - string[] args = message.Split((char[]) null, StringSplitOptions.RemoveEmptyEntries); - switch (args[0]) { - case "!2fa": - return Response2FA(steamID, args[1]); - case "!2fano": - return await Response2FAConfirm(steamID, args[1], false).ConfigureAwait(false); - case "!2faoff": - return Response2FAOff(steamID, args[1]); - case "!2faok": - return await Response2FAConfirm(steamID, args[1], true).ConfigureAwait(false); - case "!addlicense": - if (args.Length > 2) { - return await ResponseAddLicense(steamID, args[1], args[2]).ConfigureAwait(false); - } else { - return await ResponseAddLicense(steamID, BotName, args[1]).ConfigureAwait(false); - } - case "!farm": - return ResponseFarm(steamID, args[1]); - case "!loot": - return await ResponseSendTrade(steamID, args[1]).ConfigureAwait(false); - case "!owns": - if (args.Length > 2) { - return await ResponseOwns(steamID, args[1], args[2]).ConfigureAwait(false); - } else { - return await ResponseOwns(steamID, BotName, args[1]).ConfigureAwait(false); - } - case "!pause": - return await ResponsePause(steamID, args[1]).ConfigureAwait(false); - case "!play": - if (args.Length > 2) { - return await ResponsePlay(steamID, args[1], args[2]).ConfigureAwait(false); - } else { - return await ResponsePlay(steamID, BotName, args[1]).ConfigureAwait(false); - } - case "!redeem": - if (args.Length > 2) { - return await ResponseRedeem(steamID, args[1], args[2].Replace(",", Environment.NewLine), false).ConfigureAwait(false); - } else { - return await ResponseRedeem(steamID, BotName, args[1].Replace(",", Environment.NewLine), false).ConfigureAwait(false); - } - case "!start": - return await ResponseStart(steamID, args[1]).ConfigureAwait(false); - case "!status": - return ResponseStatus(steamID, args[1]); - case "!stop": - return ResponseStop(steamID, args[1]); - default: - return ResponseUnknown(steamID); - } + } + + string[] args = message.Split((char[]) null, StringSplitOptions.RemoveEmptyEntries); + switch (args[0]) { + case "!2fa": + return Response2FA(steamID, args[1]); + case "!2fano": + return await Response2FAConfirm(steamID, args[1], false).ConfigureAwait(false); + case "!2faoff": + return Response2FAOff(steamID, args[1]); + case "!2faok": + return await Response2FAConfirm(steamID, args[1], true).ConfigureAwait(false); + case "!addlicense": + if (args.Length > 2) { + return await ResponseAddLicense(steamID, args[1], args[2]).ConfigureAwait(false); + } + + return await ResponseAddLicense(steamID, BotName, args[1]).ConfigureAwait(false); + case "!farm": + return ResponseFarm(steamID, args[1]); + case "!loot": + return await ResponseSendTrade(steamID, args[1]).ConfigureAwait(false); + case "!owns": + if (args.Length > 2) { + return await ResponseOwns(steamID, args[1], args[2]).ConfigureAwait(false); + } + + return await ResponseOwns(steamID, BotName, args[1]).ConfigureAwait(false); + case "!pause": + return await ResponsePause(steamID, args[1]).ConfigureAwait(false); + case "!play": + if (args.Length > 2) { + return await ResponsePlay(steamID, args[1], args[2]).ConfigureAwait(false); + } + + return await ResponsePlay(steamID, BotName, args[1]).ConfigureAwait(false); + case "!redeem": + if (args.Length > 2) { + return await ResponseRedeem(steamID, args[1], args[2].Replace(",", Environment.NewLine), false).ConfigureAwait(false); + } + + return await ResponseRedeem(steamID, BotName, args[1].Replace(",", Environment.NewLine), false).ConfigureAwait(false); + case "!start": + return await ResponseStart(steamID, args[1]).ConfigureAwait(false); + case "!status": + return ResponseStatus(steamID, args[1]); + case "!stop": + return ResponseStop(steamID, args[1]); + default: + return ResponseUnknown(steamID); } } @@ -434,7 +427,7 @@ namespace ArchiSteamFarm { } // 2FA tokens are expiring soon, don't use limiter when user is providing one - if (TwoFactorCode == null || BotDatabase.SteamGuardAccount != null) { + if ((TwoFactorCode == null) || (BotDatabase.SteamGuardAccount != null)) { await LimitLoginRequestsAsync().ConfigureAwait(false); } @@ -458,11 +451,11 @@ namespace ArchiSteamFarm { return false; } - return steamID == BotConfig.SteamMasterID || IsOwner(steamID); + return (steamID == BotConfig.SteamMasterID) || IsOwner(steamID); } private void ImportAuthenticator(string maFilePath) { - if (BotDatabase.SteamGuardAccount != null || !File.Exists(maFilePath)) { + if ((BotDatabase.SteamGuardAccount != null) || !File.Exists(maFilePath)) { return; } @@ -500,6 +493,7 @@ namespace ArchiSteamFarm { BotDatabase.SteamGuardAccount = null; return; } + break; default: BotDatabase.SteamGuardAccount = null; @@ -526,69 +520,75 @@ namespace ArchiSteamFarm { } private async Task ResponsePause(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } if (CardsFarmer.ManualMode) { await CardsFarmer.SwitchToManualMode(false).ConfigureAwait(false); return "Automatic farming is enabled again!"; - } else { - await CardsFarmer.SwitchToManualMode(true).ConfigureAwait(false); - return "Automatic farming is now stopped!"; } + + await CardsFarmer.SwitchToManualMode(true).ConfigureAwait(false); + return "Automatic farming is now stopped!"; } private static async Task ResponsePause(ulong steamID, string botName) { - if (steamID == 0 || string.IsNullOrEmpty(botName)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return await bot.ResponsePause(steamID).ConfigureAwait(false); } - return await bot.ResponsePause(steamID).ConfigureAwait(false); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private string ResponseStatus(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } if (CardsFarmer.CurrentGamesFarming.Count > 0) { return "Bot " + BotName + " is farming appIDs: " + string.Join(", ", CardsFarmer.CurrentGamesFarming) + " and has a total of " + CardsFarmer.GamesToFarm.Count + " games left to farm."; - } else if (CardsFarmer.ManualMode) { - return "Bot " + BotName + " is running in manual mode."; - } else if (SteamClient.IsConnected) { - return "Bot " + BotName + " is not farming anything."; - } else if (KeepRunning) { - return "Bot " + BotName + " is not connected."; - } else { - return "Bot " + BotName + " is not running."; } + + if (CardsFarmer.ManualMode) { + return "Bot " + BotName + " is running in manual mode."; + } + + if (SteamClient.IsConnected) { + return "Bot " + BotName + " is not farming anything."; + } + + if (KeepRunning) { + return "Bot " + BotName + " is not connected."; + } + + return "Bot " + BotName + " is not running."; } private static string ResponseStatus(ulong steamID, string botName) { - if (steamID == 0 || string.IsNullOrEmpty(botName)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return bot.ResponseStatus(steamID); } - return bot.ResponseStatus(steamID); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private static string ResponseStatusAll(ulong steamID) { @@ -615,7 +615,7 @@ namespace ArchiSteamFarm { } private async Task ResponseSendTrade(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } @@ -626,45 +626,45 @@ namespace ArchiSteamFarm { await Trading.LimitInventoryRequestsAsync().ConfigureAwait(false); HashSet inventory = await ArchiWebHandler.GetMyTradableInventory().ConfigureAwait(false); - if (inventory == null || inventory.Count == 0) { + if ((inventory == null) || (inventory.Count == 0)) { return "Nothing to send, inventory seems empty!"; } // Remove from our pending inventory all items that are not steam cards and boosters - inventory.RemoveWhere(item => item.Type != Steam.Item.EType.TradingCard && item.Type != Steam.Item.EType.FoilTradingCard && item.Type != Steam.Item.EType.BoosterPack); + inventory.RemoveWhere(item => (item.Type != Steam.Item.EType.TradingCard) && (item.Type != Steam.Item.EType.FoilTradingCard) && (item.Type != Steam.Item.EType.BoosterPack)); inventory.TrimExcess(); if (inventory.Count == 0) { return "Nothing to send, inventory seems empty!"; } - if (await ArchiWebHandler.SendTradeOffer(inventory, BotConfig.SteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) { - await AcceptConfirmations(true, Confirmation.ConfirmationType.Trade).ConfigureAwait(false); - return "Trade offer sent successfully!"; - } else { + if (!await ArchiWebHandler.SendTradeOffer(inventory, BotConfig.SteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) { return "Trade offer failed due to error!"; } + + await AcceptConfirmations(true, Confirmation.ConfirmationType.Trade).ConfigureAwait(false); + return "Trade offer sent successfully!"; } private static async Task ResponseSendTrade(ulong steamID, string botName) { - if (steamID == 0 || string.IsNullOrEmpty(botName)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return await bot.ResponseSendTrade(steamID).ConfigureAwait(false); } - return await bot.ResponseSendTrade(steamID).ConfigureAwait(false); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private string Response2FA(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } @@ -677,24 +677,24 @@ namespace ArchiSteamFarm { } private static string Response2FA(ulong steamID, string botName) { - if (steamID == 0 || string.IsNullOrEmpty(botName)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return bot.Response2FA(steamID); } - return bot.Response2FA(steamID); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private string Response2FAOff(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } @@ -702,32 +702,28 @@ namespace ArchiSteamFarm { return "That bot doesn't have ASF 2FA enabled!"; } - if (DelinkMobileAuthenticator()) { - return "Done! Bot is no longer using ASF 2FA"; - } else { - return "Something went wrong during delinking mobile authenticator!"; - } + return DelinkMobileAuthenticator() ? "Done! Bot is no longer using ASF 2FA" : "Something went wrong during delinking mobile authenticator!"; } private static string Response2FAOff(ulong steamID, string botName) { - if (steamID == 0 || string.IsNullOrEmpty(botName)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return bot.Response2FAOff(steamID); } - return bot.Response2FAOff(steamID); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private async Task Response2FAConfirm(ulong steamID, bool confirm) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } @@ -740,20 +736,20 @@ namespace ArchiSteamFarm { } private static async Task Response2FAConfirm(ulong steamID, string botName, bool confirm) { - if (steamID == 0 || string.IsNullOrEmpty(botName)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return await bot.Response2FAConfirm(steamID, confirm).ConfigureAwait(false); } - return await bot.Response2FAConfirm(steamID, confirm).ConfigureAwait(false); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private static string ResponseExit(ulong steamID) { @@ -775,7 +771,7 @@ namespace ArchiSteamFarm { } private string ResponseFarm(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } @@ -788,24 +784,24 @@ namespace ArchiSteamFarm { } private static string ResponseFarm(ulong steamID, string botName) { - if (steamID == 0 || string.IsNullOrEmpty(botName)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return bot.ResponseFarm(steamID); } - return bot.ResponseFarm(steamID); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private string ResponseHelp(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } @@ -813,7 +809,7 @@ namespace ArchiSteamFarm { } private async Task ResponseRedeem(ulong steamID, string message, bool validate) { - if (steamID == 0 || string.IsNullOrEmpty(message) || !IsMaster(steamID)) { + if ((steamID == 0) || string.IsNullOrEmpty(message) || !IsMaster(steamID)) { return null; } @@ -822,7 +818,7 @@ namespace ArchiSteamFarm { using (IEnumerator iterator = Bots.Values.GetEnumerator()) { string key = reader.ReadLine(); Bot currentBot = this; - while (!string.IsNullOrEmpty(key) && currentBot != null) { + while (!string.IsNullOrEmpty(key) && (currentBot != null)) { if (validate && !IsValidCdKey(key)) { key = reader.ReadLine(); // Next key continue; // Keep current bot @@ -845,9 +841,9 @@ namespace ArchiSteamFarm { if (result.PurchaseResult == ArchiHandler.PurchaseResponseCallback.EPurchaseResult.OK) { break; // Next bot (if needed) - } else { - continue; // Keep current bot } + + continue; // Keep current bot case ArchiHandler.PurchaseResponseCallback.EPurchaseResult.AlreadyOwned: case ArchiHandler.PurchaseResponseCallback.EPurchaseResult.BaseGameRequired: case ArchiHandler.PurchaseResponseCallback.EPurchaseResult.OnCooldown: @@ -864,11 +860,7 @@ namespace ArchiSteamFarm { } bool alreadyHandled = false; - foreach (Bot bot in Bots.Values) { - if (bot == this || !bot.SteamClient.IsConnected) { - continue; - } - + foreach (Bot bot in Bots.Values.Where(bot => (bot != this) && bot.SteamClient.IsConnected)) { ArchiHandler.PurchaseResponseCallback otherResult = await bot.ArchiHandler.RedeemKey(key).ConfigureAwait(false); if (otherResult == null) { continue; @@ -895,40 +887,33 @@ namespace ArchiSteamFarm { } } - if (BotConfig.DistributeKeys) { - do { - if (iterator.MoveNext()) { - currentBot = iterator.Current; - } else { - currentBot = null; - } - } while (currentBot == this || (currentBot != null && !currentBot.SteamClient.IsConnected)); + if (!BotConfig.DistributeKeys) { + continue; } + + do { + currentBot = iterator.MoveNext() ? iterator.Current : null; + } while ((currentBot == this) || ((currentBot != null) && !currentBot.SteamClient.IsConnected)); } } - if (response.Length == 0) { - return null; - } - - return response.ToString(); + return response.Length == 0 ? null : response.ToString(); } private static async Task ResponseRedeem(ulong steamID, string botName, string message, bool validate) { - if (steamID == 0 || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(message)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(message)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return await bot.ResponseRedeem(steamID, message, validate).ConfigureAwait(false); + } + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; } - return await bot.ResponseRedeem(steamID, message, validate).ConfigureAwait(false); + return null; } private static string ResponseRejoinChat(ulong steamID) { @@ -965,8 +950,8 @@ namespace ArchiSteamFarm { return "Done!"; } - private async Task ResponseAddLicense(ulong steamID, HashSet gameIDs) { - if (steamID == 0 || gameIDs == null || gameIDs.Count == 0 || !SteamClient.IsConnected || !IsMaster(steamID)) { + private async Task ResponseAddLicense(ulong steamID, ICollection gameIDs) { + if ((steamID == 0) || (gameIDs == null) || (gameIDs.Count == 0) || !SteamClient.IsConnected || !IsMaster(steamID)) { return null; } @@ -984,7 +969,7 @@ namespace ArchiSteamFarm { } private static async Task ResponseAddLicense(ulong steamID, string botName, string games) { - if (steamID == 0 || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(games)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(games)) { return null; } @@ -992,19 +977,15 @@ namespace ArchiSteamFarm { if (!Bots.TryGetValue(botName, out bot)) { if (IsOwner(steamID)) { return "Couldn't find any bot named " + botName + "!"; - } else { - return null; } + + return null; } - string[] gameIDs = games.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + string[] gameIDs = games.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); HashSet gamesToRedeem = new HashSet(); - foreach (string game in gameIDs) { - if (string.IsNullOrEmpty(game)) { - continue; - } - + foreach (string game in gameIDs.Where(game => !string.IsNullOrEmpty(game))) { uint gameID; if (!uint.TryParse(game, out gameID)) { continue; @@ -1021,7 +1002,7 @@ namespace ArchiSteamFarm { } private async Task ResponseOwns(ulong steamID, string query) { - if (steamID == 0 || string.IsNullOrEmpty(query) || !IsMaster(steamID)) { + if ((steamID == 0) || string.IsNullOrEmpty(query) || !IsMaster(steamID)) { return null; } @@ -1032,18 +1013,14 @@ namespace ArchiSteamFarm { ownedGames = await ArchiWebHandler.GetOwnedGames().ConfigureAwait(false); } - if (ownedGames == null || ownedGames.Count == 0) { + if ((ownedGames == null) || (ownedGames.Count == 0)) { return "List of owned games is empty!"; } StringBuilder response = new StringBuilder(); - string[] games = query.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string game in games) { - if (string.IsNullOrEmpty(game)) { - continue; - } - + string[] games = query.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach (string game in games.Where(game => !string.IsNullOrEmpty(game))) { // Check if this is appID uint appID; if (uint.TryParse(game, out appID)) { @@ -1058,53 +1035,52 @@ namespace ArchiSteamFarm { } // This is a string, so check our entire library - foreach (KeyValuePair ownedGame in ownedGames) { - if (ownedGame.Value.IndexOf(game, StringComparison.OrdinalIgnoreCase) < 0) { - continue; - } - + foreach (KeyValuePair ownedGame in ownedGames.Where(ownedGame => ownedGame.Value.IndexOf(game, StringComparison.OrdinalIgnoreCase) >= 0)) { response.Append(Environment.NewLine + "Owned already: " + ownedGame.Key + " | " + ownedGame.Value); } } if (response.Length > 0) { return response.ToString(); - } else { - return "Not owned yet: " + query; } + + return "Not owned yet: " + query; } private static async Task ResponseOwns(ulong steamID, string botName, string query) { - if (steamID == 0 || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(query)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(query)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return await bot.ResponseOwns(steamID, query).ConfigureAwait(false); } - return await bot.ResponseOwns(steamID, query).ConfigureAwait(false); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private async Task ResponsePlay(ulong steamID, HashSet gameIDs) { - if (steamID == 0 || gameIDs == null || gameIDs.Count == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || (gameIDs == null) || (gameIDs.Count == 0) || !IsMaster(steamID)) { return null; } if (gameIDs.Contains(0)) { - if (CardsFarmer.ManualMode) { - ResetGamesPlayed(); - await CardsFarmer.SwitchToManualMode(false).ConfigureAwait(false); + if (!CardsFarmer.ManualMode) { + return "Done!"; } + + ResetGamesPlayed(); + await CardsFarmer.SwitchToManualMode(false).ConfigureAwait(false); } else { if (!CardsFarmer.ManualMode) { await CardsFarmer.SwitchToManualMode(true).ConfigureAwait(false); } + ArchiHandler.PlayGames(gameIDs); } @@ -1112,7 +1088,7 @@ namespace ArchiSteamFarm { } private static async Task ResponsePlay(ulong steamID, string botName, string games) { - if (steamID == 0 || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(games)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(games)) { return null; } @@ -1120,19 +1096,15 @@ namespace ArchiSteamFarm { if (!Bots.TryGetValue(botName, out bot)) { if (IsOwner(steamID)) { return "Couldn't find any bot named " + botName + "!"; - } else { - return null; } + + return null; } - string[] gameIDs = games.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + string[] gameIDs = games.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); HashSet gamesToPlay = new HashSet(); - foreach (string game in gameIDs) { - if (string.IsNullOrEmpty(game)) { - continue; - } - + foreach (string game in gameIDs.Where(game => !string.IsNullOrEmpty(game))) { uint gameID; if (!uint.TryParse(game, out gameID)) { continue; @@ -1149,7 +1121,7 @@ namespace ArchiSteamFarm { } private async Task ResponseStart(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } @@ -1162,24 +1134,24 @@ namespace ArchiSteamFarm { } private static async Task ResponseStart(ulong steamID, string botName) { - if (steamID == 0 || string.IsNullOrEmpty(botName)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return await bot.ResponseStart(steamID).ConfigureAwait(false); } - return await bot.ResponseStart(steamID).ConfigureAwait(false); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private string ResponseStop(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } @@ -1192,24 +1164,24 @@ namespace ArchiSteamFarm { } private static string ResponseStop(ulong steamID, string botName) { - if (steamID == 0 || string.IsNullOrEmpty(botName)) { + if ((steamID == 0) || string.IsNullOrEmpty(botName)) { return null; } Bot bot; - if (!Bots.TryGetValue(botName, out bot)) { - if (IsOwner(steamID)) { - return "Couldn't find any bot named " + botName + "!"; - } else { - return null; - } + if (Bots.TryGetValue(botName, out bot)) { + return bot.ResponseStop(steamID); } - return bot.ResponseStop(steamID); + if (IsOwner(steamID)) { + return "Couldn't find any bot named " + botName + "!"; + } + + return null; } private string ResponseUnknown(ulong steamID) { - if (steamID == 0 || !IsMaster(steamID)) { + if ((steamID == 0) || !IsMaster(steamID)) { return null; } @@ -1241,7 +1213,7 @@ namespace ArchiSteamFarm { } private async Task HandleMessage(ulong chatID, ulong steamID, string message) { - if (chatID == 0 || steamID == 0 || string.IsNullOrEmpty(message)) { + if ((chatID == 0) || (steamID == 0) || string.IsNullOrEmpty(message)) { return; } @@ -1249,7 +1221,7 @@ namespace ArchiSteamFarm { } private void SendMessage(ulong steamID, string message) { - if (steamID == 0 || string.IsNullOrEmpty(message)) { + if ((steamID == 0) || string.IsNullOrEmpty(message)) { return; } @@ -1261,7 +1233,7 @@ namespace ArchiSteamFarm { } private void SendMessageToChannel(ulong steamID, string message) { - if (steamID == 0 || string.IsNullOrEmpty(message) || !SteamClient.IsConnected) { + if ((steamID == 0) || string.IsNullOrEmpty(message) || !SteamClient.IsConnected) { return; } @@ -1272,7 +1244,7 @@ namespace ArchiSteamFarm { } private void SendMessageToUser(ulong steamID, string message) { - if (steamID == 0 || string.IsNullOrEmpty(message) || !SteamClient.IsConnected) { + if ((steamID == 0) || string.IsNullOrEmpty(message) || !SteamClient.IsConnected) { return; } @@ -1302,6 +1274,7 @@ namespace ArchiSteamFarm { if (string.IsNullOrEmpty(userLogin.EmailCode)) { return; } + break; default: Logging.LogGenericError("Unhandled situation: " + loginResult, BotName); @@ -1319,6 +1292,7 @@ namespace ArchiSteamFarm { if (string.IsNullOrEmpty(authenticatorLinker.PhoneNumber)) { return; } + break; default: Logging.LogGenericError("Unhandled situation: " + linkResult, BotName); @@ -1345,6 +1319,7 @@ namespace ArchiSteamFarm { DelinkMobileAuthenticator(); return; } + break; default: Logging.LogGenericError("Unhandled situation: " + finalizeResult, BotName); @@ -1366,16 +1341,16 @@ namespace ArchiSteamFarm { } // Try to deactivate authenticator, and assume we're safe to remove if it wasn't fully enrolled yet (even if request fails) - if (BotDatabase.SteamGuardAccount.DeactivateAuthenticator() || !BotDatabase.SteamGuardAccount.FullyEnrolled) { - BotDatabase.SteamGuardAccount = null; - return true; + if (!BotDatabase.SteamGuardAccount.DeactivateAuthenticator() && BotDatabase.SteamGuardAccount.FullyEnrolled) { + return false; } - return false; + BotDatabase.SteamGuardAccount = null; + return true; } private void JoinMasterChat() { - if (!SteamClient.IsConnected || BotConfig.SteamMasterClanID == 0) { + if (!SteamClient.IsConnected || (BotConfig.SteamMasterClanID == 0)) { return; } @@ -1390,14 +1365,13 @@ namespace ArchiSteamFarm { } } - if (string.IsNullOrEmpty(BotConfig.SteamPassword) && (requiresPassword || string.IsNullOrEmpty(BotDatabase.LoginKey))) { - BotConfig.SteamPassword = Program.GetUserInput(Program.EUserInputType.Password, BotName); - if (string.IsNullOrEmpty(BotConfig.SteamPassword)) { - return false; - } + if (!string.IsNullOrEmpty(BotConfig.SteamPassword) || + (!requiresPassword && !string.IsNullOrEmpty(BotDatabase.LoginKey))) { + return true; } - return true; + BotConfig.SteamPassword = Program.GetUserInput(Program.EUserInputType.Password, BotName); + return !string.IsNullOrEmpty(BotConfig.SteamPassword); } private void OnConnected(SteamClient.ConnectedCallback callback) { @@ -1513,31 +1487,23 @@ namespace ArchiSteamFarm { Logging.LogGenericInfo("Reconnecting...", BotName); // 2FA tokens are expiring soon, don't use limiter when user is providing one - if (TwoFactorCode == null || BotDatabase.SteamGuardAccount != null) { + if ((TwoFactorCode == null) || (BotDatabase.SteamGuardAccount != null)) { await LimitLoginRequestsAsync().ConfigureAwait(false); } SteamClient.Connect(); } - private void OnFreeLicense(SteamApps.FreeLicenseCallback callback) { - if (callback == null) { - return; - } - } + // ReSharper disable once MemberCanBeMadeStatic.Local + private void OnFreeLicense(SteamApps.FreeLicenseCallback callback) { } private async void OnGuestPassList(SteamApps.GuestPassListCallback callback) { - if (callback == null || callback.Result != EResult.OK || callback.CountGuestPassesToRedeem == 0 || callback.GuestPasses.Count == 0 || !BotConfig.AcceptGifts) { + if ((callback == null) || (callback.Result != EResult.OK) || (callback.CountGuestPassesToRedeem == 0) || (callback.GuestPasses.Count == 0) || !BotConfig.AcceptGifts) { return; } bool acceptedSomething = false; - foreach (KeyValue guestPass in callback.GuestPasses) { - ulong gid = guestPass["gid"].AsUnsignedLong(); - if (gid == 0) { - continue; - } - + foreach (ulong gid in callback.GuestPasses.Select(guestPass => guestPass["gid"].AsUnsignedLong()).Where(gid => gid != 0)) { Logging.LogGenericInfo("Accepting gift: " + gid + "...", BotName); if (await ArchiWebHandler.AcceptGift(gid).ConfigureAwait(false)) { acceptedSomething = true; @@ -1553,7 +1519,7 @@ namespace ArchiSteamFarm { } private void OnChatInvite(SteamFriends.ChatInviteCallback callback) { - if (callback == null || !IsMaster(callback.PatronID)) { + if ((callback == null) || !IsMaster(callback.PatronID)) { return; } @@ -1561,7 +1527,7 @@ namespace ArchiSteamFarm { } private async void OnChatMsg(SteamFriends.ChatMsgCallback callback) { - if (callback == null || callback.ChatMsgType != EChatEntryType.ChatMsg) { + if ((callback == null) || (callback.ChatMsgType != EChatEntryType.ChatMsg)) { return; } @@ -1584,11 +1550,7 @@ namespace ArchiSteamFarm { return; } - foreach (var friend in callback.FriendList) { - if (friend.Relationship != EFriendRelationship.RequestRecipient) { - continue; - } - + foreach (SteamFriends.FriendsListCallback.Friend friend in callback.FriendList.Where(friend => friend.Relationship == EFriendRelationship.RequestRecipient)) { switch (friend.SteamID.AccountType) { case EAccountType.Clan: // TODO: Accept clan invites from master? @@ -1605,7 +1567,7 @@ namespace ArchiSteamFarm { } private async void OnFriendMsg(SteamFriends.FriendMsgCallback callback) { - if (callback == null || callback.EntryType != EChatEntryType.ChatMsg) { + if ((callback == null) || (callback.EntryType != EChatEntryType.ChatMsg)) { return; } @@ -1613,12 +1575,12 @@ namespace ArchiSteamFarm { } private async void OnFriendMsgHistory(SteamFriends.FriendMsgHistoryCallback callback) { - if (callback == null || callback.Result != EResult.OK || callback.Messages.Count == 0 || !IsMaster(callback.SteamID)) { + if ((callback == null) || (callback.Result != EResult.OK) || (callback.Messages.Count == 0) || !IsMaster(callback.SteamID)) { return; } // Get last message - var lastMessage = callback.Messages[callback.Messages.Count - 1]; + SteamFriends.FriendMsgHistoryCallback.FriendMessage lastMessage = callback.Messages[callback.Messages.Count - 1]; // If message is read already, return if (!lastMessage.Unread) { @@ -1670,19 +1632,19 @@ namespace ArchiSteamFarm { AuthCode = Program.GetUserInput(Program.EUserInputType.SteamGuard, BotName); if (string.IsNullOrEmpty(AuthCode)) { Stop(); - return; } + break; case EResult.AccountLoginDeniedNeedTwoFactor: if (BotDatabase.SteamGuardAccount == null) { TwoFactorCode = Program.GetUserInput(Program.EUserInputType.TwoFactorAuthentication, BotName); if (string.IsNullOrEmpty(TwoFactorCode)) { Stop(); - return; } } else { Logging.LogGenericWarning("2FA code was invalid despite of using ASF 2FA. Invalid authenticator or bad timing?", BotName); } + break; case EResult.InvalidPassword: InvalidPassword = true; @@ -1700,7 +1662,7 @@ namespace ArchiSteamFarm { string maFilePath = Path.Combine(Program.ConfigDirectory, callback.ClientSteamID.ConvertToUInt64() + ".maFile"); if (File.Exists(maFilePath)) { ImportAuthenticator(maFilePath); - } else if (TwoFactorCode == null && BotConfig.UseAsfAsMobileAuthenticator) { + } else if ((TwoFactorCode == null) && BotConfig.UseAsfAsMobileAuthenticator) { LinkMobileAuthenticator(); } } @@ -1801,20 +1763,17 @@ namespace ArchiSteamFarm { }); } - private void OnWebAPIUserNonce(SteamUser.WebAPIUserNonceCallback callback) { - if (callback == null) { - return; - } - } + // ReSharper disable once MemberCanBeMadeStatic.Local + private void OnWebAPIUserNonce(SteamUser.WebAPIUserNonceCallback callback) { } private async void OnNotifications(ArchiHandler.NotificationsCallback callback) { - if (callback == null || callback.Notifications == null) { + if ((callback == null) || (callback.Notifications == null)) { return; } bool checkTrades = false; bool markInventory = false; - foreach (var notification in callback.Notifications) { + foreach (ArchiHandler.NotificationsCallback.ENotification notification in callback.Notifications) { switch (notification) { case ArchiHandler.NotificationsCallback.ENotification.Items: markInventory = true; @@ -1835,7 +1794,7 @@ namespace ArchiSteamFarm { } private void OnOfflineMessage(ArchiHandler.OfflineMessageCallback callback) { - if (callback == null || callback.OfflineMessagesCount == 0) { + if ((callback == null) || (callback.OfflineMessagesCount == 0)) { return; } diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index 2fc3838bf..73fa48bca 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -28,6 +28,8 @@ using System.Collections.Generic; using System.IO; namespace ArchiSteamFarm { + // ReSharper disable once ClassCannotBeInstantiated + // ReSharper disable once ClassNeverInstantiated.Global internal sealed class BotConfig { [JsonProperty(Required = Required.DisallowNull)] internal bool Enabled { get; private set; } = false; @@ -36,10 +38,10 @@ namespace ArchiSteamFarm { internal bool StartOnLaunch { get; private set; } = true; [JsonProperty] - internal string SteamLogin { get; set; } = null; + internal string SteamLogin { get; set; } [JsonProperty] - internal string SteamPassword { get; set; } = null; + internal string SteamPassword { get; set; } [JsonProperty] internal string SteamParentalPIN { get; set; } = "0"; @@ -99,7 +101,7 @@ namespace ArchiSteamFarm { internal string CustomGamePlayedWhileIdle { get; private set; } = null; [JsonProperty(Required = Required.DisallowNull)] - internal HashSet GamesPlayedWhileIdle { get; private set; } = new HashSet() { 0 }; + internal HashSet GamesPlayedWhileIdle { get; private set; } = new HashSet { 0 }; internal static BotConfig Load(string filePath) { diff --git a/ArchiSteamFarm/BotDatabase.cs b/ArchiSteamFarm/BotDatabase.cs index 3deb31012..ec3a046e4 100644 --- a/ArchiSteamFarm/BotDatabase.cs +++ b/ArchiSteamFarm/BotDatabase.cs @@ -93,7 +93,7 @@ namespace ArchiSteamFarm { // This constructor is used when creating new database private BotDatabase(string filePath) { if (string.IsNullOrEmpty(filePath)) { - throw new ArgumentNullException("filePath"); + throw new ArgumentNullException(nameof(filePath)); } FilePath = filePath; @@ -101,6 +101,7 @@ namespace ArchiSteamFarm { } // This constructor is used only by deserializer + // ReSharper disable once UnusedMember.Local private BotDatabase() { } internal void Save() { diff --git a/ArchiSteamFarm/CardsFarmer.cs b/ArchiSteamFarm/CardsFarmer.cs index aec3c56b2..52995684f 100755 --- a/ArchiSteamFarm/CardsFarmer.cs +++ b/ArchiSteamFarm/CardsFarmer.cs @@ -48,12 +48,12 @@ namespace ArchiSteamFarm { internal CardsFarmer(Bot bot) { if (bot == null) { - throw new ArgumentNullException("bot"); + throw new ArgumentNullException(nameof(bot)); } Bot = bot; - if (Timer == null && Program.GlobalConfig.IdleFarmingPeriod > 0) { + if ((Timer == null) && (Program.GlobalConfig.IdleFarmingPeriod > 0)) { Timer = new Timer( async e => await CheckGamesForFarming().ConfigureAwait(false), null, @@ -132,10 +132,12 @@ namespace ArchiSteamFarm { Logging.LogGenericInfo("Chosen farming algorithm: Simple", Bot.BotName); while (GamesToFarm.Count > 0) { uint appID = GamesToFarm.Keys.FirstOrDefault(); - if (!await FarmSolo(appID).ConfigureAwait(false)) { - NowFarming = false; - return; + if (await FarmSolo(appID).ConfigureAwait(false)) { + continue; } + + NowFarming = false; + return; } } } while (await IsAnythingToFarm().ConfigureAwait(false)); @@ -164,7 +166,7 @@ namespace ArchiSteamFarm { FarmResetEvent.Set(); Logging.LogGenericInfo("Waiting for reaction...", Bot.BotName); - for (byte i = 0; i < Program.GlobalConfig.HttpTimeout && NowFarming; i++) { + for (byte i = 0; (i < Program.GlobalConfig.HttpTimeout) && NowFarming; i++) { await Utilities.SleepAsync(1000).ConfigureAwait(false); } @@ -188,10 +190,8 @@ namespace ArchiSteamFarm { } HashSet result = new HashSet(); - foreach (KeyValuePair keyValue in gamesToFarm) { - if (keyValue.Value >= 2) { - result.Add(keyValue.Key); - } + foreach (KeyValuePair keyValue in gamesToFarm.Where(keyValue => keyValue.Value >= 2)) { + result.Add(keyValue.Key); } return result; @@ -210,7 +210,7 @@ namespace ArchiSteamFarm { byte maxPages = 1; HtmlNodeCollection htmlNodeCollection = htmlDocument.DocumentNode.SelectNodes("//a[@class='pagelink']"); - if (htmlNodeCollection != null && htmlNodeCollection.Count > 0) { + if ((htmlNodeCollection != null) && (htmlNodeCollection.Count > 0)) { HtmlNode htmlNode = htmlNodeCollection[htmlNodeCollection.Count - 1]; string lastPage = htmlNode.InnerText; if (!string.IsNullOrEmpty(lastPage)) { @@ -224,16 +224,19 @@ namespace ArchiSteamFarm { CheckPage(htmlDocument); - if (maxPages > 1) { - Logging.LogGenericInfo("Checking other pages...", Bot.BotName); - List tasks = new List(maxPages - 1); - for (byte page = 2; page <= maxPages; page++) { - byte currentPage = page; // We need a copy of variable being passed when in for loops, as loop will proceed before task is launched - tasks.Add(CheckPage(currentPage)); - } - await Task.WhenAll(tasks).ConfigureAwait(false); + if (maxPages <= 1) { + return GamesToFarm.Count > 0; } + Logging.LogGenericInfo("Checking other pages...", Bot.BotName); + + List tasks = new List(maxPages - 1); + for (byte page = 2; page <= maxPages; page++) { + byte currentPage = page; // We need a copy of variable being passed when in for loops, as loop will proceed before task is launched + tasks.Add(CheckPage(currentPage)); + } + + await Task.WhenAll(tasks).ConfigureAwait(false); return GamesToFarm.Count > 0; } @@ -370,15 +373,11 @@ namespace ArchiSteamFarm { } Logging.LogGenericInfo("Now farming: " + string.Join(", ", CurrentGamesFarming), Bot.BotName); - if (FarmHours(maxHour, CurrentGamesFarming)) { - CurrentGamesFarming.Clear(); - CurrentGamesFarming.TrimExcess(); - return true; - } else { - CurrentGamesFarming.Clear(); - CurrentGamesFarming.TrimExcess(); - return false; - } + + bool result = FarmHours(maxHour, CurrentGamesFarming); + CurrentGamesFarming.Clear(); + CurrentGamesFarming.TrimExcess(); + return result; } private async Task FarmSolo(uint appID) { @@ -389,20 +388,23 @@ namespace ArchiSteamFarm { CurrentGamesFarming.Add(appID); Logging.LogGenericInfo("Now farming: " + appID, Bot.BotName); - if (await Farm(appID).ConfigureAwait(false)) { - CurrentGamesFarming.Clear(); - CurrentGamesFarming.TrimExcess(); - float hours; - if (GamesToFarm.TryRemove(appID, out hours)) { - TimeSpan timeSpan = TimeSpan.FromHours(hours); - Logging.LogGenericInfo("Done farming: " + appID + " after " + timeSpan.ToString(@"hh\:mm") + " hours of playtime!", Bot.BotName); - } - return true; - } else { - CurrentGamesFarming.Clear(); - CurrentGamesFarming.TrimExcess(); + + bool result = await Farm(appID).ConfigureAwait(false); + CurrentGamesFarming.Clear(); + CurrentGamesFarming.TrimExcess(); + + if (!result) { return false; } + + float hours; + if (!GamesToFarm.TryRemove(appID, out hours)) { + return false; + } + + TimeSpan timeSpan = TimeSpan.FromHours(hours); + Logging.LogGenericInfo("Done farming: " + appID + " after " + timeSpan.ToString(@"hh\:mm") + " hours of playtime!", Bot.BotName); + return true; } private async Task Farm(uint appID) { @@ -415,7 +417,7 @@ namespace ArchiSteamFarm { bool success = true; bool? keepFarming = await ShouldFarm(appID).ConfigureAwait(false); - for (ushort farmingTime = 0; farmingTime <= 60 * Program.GlobalConfig.MaxFarmingTime && keepFarming.GetValueOrDefault(true); farmingTime += Program.GlobalConfig.FarmingDelay) { + for (ushort farmingTime = 0; (farmingTime <= 60 * Program.GlobalConfig.MaxFarmingTime) && keepFarming.GetValueOrDefault(true); farmingTime += Program.GlobalConfig.FarmingDelay) { if (FarmResetEvent.Wait(60 * 1000 * Program.GlobalConfig.FarmingDelay)) { success = false; break; @@ -435,7 +437,7 @@ namespace ArchiSteamFarm { } private bool FarmHours(float maxHour, HashSet appIDs) { - if (maxHour < 0 || appIDs == null || appIDs.Count == 0) { + if ((maxHour < 0) || (appIDs == null) || (appIDs.Count == 0)) { return false; } diff --git a/ArchiSteamFarm/Debugging.cs b/ArchiSteamFarm/Debugging.cs index b5500c927..42d28896c 100644 --- a/ArchiSteamFarm/Debugging.cs +++ b/ArchiSteamFarm/Debugging.cs @@ -29,14 +29,14 @@ using System.IO; namespace ArchiSteamFarm { internal static class Debugging { #if DEBUG + // ReSharper disable once ConvertToConstant.Global internal static readonly bool IsDebugBuild = true; #else + // ReSharper disable once ConvertToConstant.Global internal static readonly bool IsDebugBuild = false; #endif - internal static bool IsReleaseBuild => !IsDebugBuild; - - internal static bool NetHookAlreadyInitialized { get; set; } = false; + internal static bool NetHookAlreadyInitialized { get; set; } internal sealed class DebugListener : IDebugListener { private readonly string FilePath; diff --git a/ArchiSteamFarm/GlobalConfig.cs b/ArchiSteamFarm/GlobalConfig.cs index ad4b71dc9..a1c7e34bd 100644 --- a/ArchiSteamFarm/GlobalConfig.cs +++ b/ArchiSteamFarm/GlobalConfig.cs @@ -25,11 +25,15 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Sockets; namespace ArchiSteamFarm { + // ReSharper disable once ClassCannotBeInstantiated + // ReSharper disable once ClassNeverInstantiated.Global internal sealed class GlobalConfig { + [SuppressMessage("ReSharper", "UnusedMember.Global")] internal enum EUpdateChannel : byte { Unknown, Stable, @@ -160,11 +164,13 @@ namespace ArchiSteamFarm { globalConfig.HttpTimeout = DefaultHttpTimeout; } - if (globalConfig.WCFPort == 0) { - Logging.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort + ". Value of " + DefaultWCFPort + " will be used instead"); - globalConfig.WCFPort = DefaultWCFPort; + if (globalConfig.WCFPort != 0) { + return globalConfig; } + Logging.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort + ". Value of " + DefaultWCFPort + " will be used instead"); + globalConfig.WCFPort = DefaultWCFPort; + return globalConfig; } diff --git a/ArchiSteamFarm/GlobalDatabase.cs b/ArchiSteamFarm/GlobalDatabase.cs index 634186a00..44e640ca2 100644 --- a/ArchiSteamFarm/GlobalDatabase.cs +++ b/ArchiSteamFarm/GlobalDatabase.cs @@ -75,7 +75,7 @@ namespace ArchiSteamFarm { // This constructor is used when creating new database private GlobalDatabase(string filePath) { if (string.IsNullOrEmpty(filePath)) { - throw new ArgumentNullException("filePath"); + throw new ArgumentNullException(nameof(filePath)); } FilePath = filePath; @@ -83,6 +83,7 @@ namespace ArchiSteamFarm { } // This constructor is used only by deserializer + // ReSharper disable once UnusedMember.Local private GlobalDatabase() { } private void Save() { diff --git a/ArchiSteamFarm/JSON/GitHub.cs b/ArchiSteamFarm/JSON/GitHub.cs index 208318b57..11461a111 100644 --- a/ArchiSteamFarm/JSON/GitHub.cs +++ b/ArchiSteamFarm/JSON/GitHub.cs @@ -22,12 +22,16 @@ */ -using Newtonsoft.Json; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; -namespace ArchiSteamFarm { +namespace ArchiSteamFarm.JSON { internal static class GitHub { + // ReSharper disable once ClassNeverInstantiated.Global + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")] internal sealed class ReleaseResponse { + // ReSharper disable once ClassNeverInstantiated.Global internal sealed class Asset { [JsonProperty(PropertyName = "name", Required = Required.Always)] internal string Name { get; private set; } diff --git a/ArchiSteamFarm/JSON/Steam.cs b/ArchiSteamFarm/JSON/Steam.cs index ab28353dd..01c6413f1 100644 --- a/ArchiSteamFarm/JSON/Steam.cs +++ b/ArchiSteamFarm/JSON/Steam.cs @@ -22,11 +22,13 @@ */ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; using Newtonsoft.Json; using SteamKit2; -using System.Collections.Generic; -namespace ArchiSteamFarm { +namespace ArchiSteamFarm.JSON { internal static class Steam { internal sealed class Item { // REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_Asset internal const ushort SteamAppID = 753; @@ -48,11 +50,13 @@ namespace ArchiSteamFarm { internal uint AppID { get; set; } + // ReSharper disable once UnusedMember.Local [JsonProperty(PropertyName = "appid", Required = Required.DisallowNull)] - internal string AppIDString { + private string AppIDString { get { return AppID.ToString(); } + set { if (string.IsNullOrEmpty(value)) { return; @@ -69,11 +73,13 @@ namespace ArchiSteamFarm { internal ulong ContextID { get; set; } + // ReSharper disable once UnusedMember.Local [JsonProperty(PropertyName = "contextid", Required = Required.DisallowNull)] - internal string ContextIDString { + private string ContextIDString { get { return ContextID.ToString(); } + set { if (string.IsNullOrEmpty(value)) { return; @@ -91,10 +97,11 @@ namespace ArchiSteamFarm { internal ulong AssetID { get; set; } [JsonProperty(PropertyName = "assetid", Required = Required.DisallowNull)] - internal string AssetIDString { + private string AssetIDString { get { return AssetID.ToString(); } + set { if (string.IsNullOrEmpty(value)) { return; @@ -109,19 +116,22 @@ namespace ArchiSteamFarm { } } + // ReSharper disable once UnusedMember.Local [JsonProperty(PropertyName = "id", Required = Required.DisallowNull)] - internal string ID { + private string ID { get { return AssetIDString; } set { AssetIDString = value; } } internal ulong ClassID { get; set; } + // ReSharper disable once UnusedMember.Local [JsonProperty(PropertyName = "classid", Required = Required.DisallowNull)] - internal string ClassIDString { + private string ClassIDString { get { return ClassID.ToString(); } + set { if (string.IsNullOrEmpty(value)) { return; @@ -138,11 +148,13 @@ namespace ArchiSteamFarm { internal ulong InstanceID { get; set; } + // ReSharper disable once UnusedMember.Local [JsonProperty(PropertyName = "instanceid", Required = Required.DisallowNull)] - internal string InstanceIDString { + private string InstanceIDString { get { return InstanceID.ToString(); } + set { if (string.IsNullOrEmpty(value)) { return; @@ -159,11 +171,13 @@ namespace ArchiSteamFarm { internal uint Amount { get; set; } + // ReSharper disable once UnusedMember.Local [JsonProperty(PropertyName = "amount", Required = Required.Always)] - internal string AmountString { + private string AmountString { get { return Amount.ToString(); } + set { if (string.IsNullOrEmpty(value)) { return; @@ -183,6 +197,7 @@ namespace ArchiSteamFarm { } internal sealed class TradeOffer { // REF: https://developer.valvesoftware.com/wiki/Steam_Web_API/IEconService#CEcon_TradeOffer + [SuppressMessage("ReSharper", "UnusedMember.Global")] internal enum ETradeOfferState : byte { Unknown, Invalid, @@ -200,11 +215,13 @@ namespace ArchiSteamFarm { internal ulong TradeOfferID { get; set; } + // ReSharper disable once UnusedMember.Local [JsonProperty(PropertyName = "tradeofferid", Required = Required.Always)] - internal string TradeOfferIDString { + private string TradeOfferIDString { get { return TradeOfferID.ToString(); } + set { if (string.IsNullOrEmpty(value)) { return; @@ -220,7 +237,7 @@ namespace ArchiSteamFarm { } [JsonProperty(PropertyName = "accountid_other", Required = Required.Always)] - internal uint OtherSteamID3 { get; set; } + internal uint OtherSteamID3 { private get; set; } [JsonProperty(PropertyName = "trade_offer_state", Required = Required.Always)] internal ETradeOfferState State { get; set; } @@ -232,82 +249,57 @@ namespace ArchiSteamFarm { internal HashSet ItemsToReceive { get; } = new HashSet(); // Extra - internal ulong OtherSteamID64 { - get { - if (OtherSteamID3 == 0) { - return 0; - } + internal ulong OtherSteamID64 => OtherSteamID3 == 0 ? 0 : new SteamID(OtherSteamID3, EUniverse.Public, EAccountType.Individual); - return new SteamID(OtherSteamID3, EUniverse.Public, EAccountType.Individual); - } - set { - if (value == 0) { - return; - } - - OtherSteamID3 = new SteamID(value).AccountID; - } - } - - internal bool IsSteamCardsOnlyTradeForUs() { - foreach (Item item in ItemsToGive) { - if (item.AppID != Item.SteamAppID || item.ContextID != Item.SteamContextID || (item.Type != Item.EType.FoilTradingCard && item.Type != Item.EType.TradingCard)) { - return false; - } - } - - return true; - } + internal bool IsSteamCardsOnlyTradeForUs() => ItemsToGive.All(item => (item.AppID == Item.SteamAppID) && (item.ContextID == Item.SteamContextID) && ((item.Type == Item.EType.FoilTradingCard) || (item.Type == Item.EType.TradingCard))); internal bool IsPotentiallyDupesTradeForUs() { - Dictionary> ItemsToGivePerGame = new Dictionary>(); + Dictionary> itemsToGivePerGame = new Dictionary>(); foreach (Item item in ItemsToGive) { - Dictionary ItemsPerType; - if (!ItemsToGivePerGame.TryGetValue(item.RealAppID, out ItemsPerType)) { - ItemsPerType = new Dictionary(); - ItemsPerType[item.Type] = item.Amount; - ItemsToGivePerGame[item.RealAppID] = ItemsPerType; + Dictionary itemsPerType; + if (!itemsToGivePerGame.TryGetValue(item.RealAppID, out itemsPerType)) { + itemsPerType = new Dictionary { [item.Type] = item.Amount }; + itemsToGivePerGame[item.RealAppID] = itemsPerType; } else { uint amount; - if (ItemsPerType.TryGetValue(item.Type, out amount)) { - ItemsPerType[item.Type] = amount + item.Amount; + if (itemsPerType.TryGetValue(item.Type, out amount)) { + itemsPerType[item.Type] = amount + item.Amount; } else { - ItemsPerType[item.Type] = item.Amount; + itemsPerType[item.Type] = item.Amount; } } } - Dictionary> ItemsToReceivePerGame = new Dictionary>(); + Dictionary> itemsToReceivePerGame = new Dictionary>(); foreach (Item item in ItemsToReceive) { - Dictionary ItemsPerType; - if (!ItemsToReceivePerGame.TryGetValue(item.RealAppID, out ItemsPerType)) { - ItemsPerType = new Dictionary(); - ItemsPerType[item.Type] = item.Amount; - ItemsToReceivePerGame[item.RealAppID] = ItemsPerType; + Dictionary itemsPerType; + if (!itemsToReceivePerGame.TryGetValue(item.RealAppID, out itemsPerType)) { + itemsPerType = new Dictionary { [item.Type] = item.Amount }; + itemsToReceivePerGame[item.RealAppID] = itemsPerType; } else { uint amount; - if (ItemsPerType.TryGetValue(item.Type, out amount)) { - ItemsPerType[item.Type] = amount + item.Amount; + if (itemsPerType.TryGetValue(item.Type, out amount)) { + itemsPerType[item.Type] = amount + item.Amount; } else { - ItemsPerType[item.Type] = item.Amount; + itemsPerType[item.Type] = item.Amount; } } } // Ensure that amount of items to give is at least amount of items to receive (per game and per type) - foreach (KeyValuePair> ItemsPerGame in ItemsToGivePerGame) { + foreach (KeyValuePair> itemsPerGame in itemsToGivePerGame) { Dictionary otherItemsPerType; - if (!ItemsToReceivePerGame.TryGetValue(ItemsPerGame.Key, out otherItemsPerType)) { + if (!itemsToReceivePerGame.TryGetValue(itemsPerGame.Key, out otherItemsPerType)) { return false; } - foreach (KeyValuePair ItemsPerType in ItemsPerGame.Value) { + foreach (KeyValuePair itemsPerType in itemsPerGame.Value) { uint otherAmount; - if (!otherItemsPerType.TryGetValue(ItemsPerType.Key, out otherAmount)) { + if (!otherItemsPerType.TryGetValue(itemsPerType.Key, out otherAmount)) { return false; } - if (ItemsPerType.Value > otherAmount) { + if (itemsPerType.Value > otherAmount) { return false; } } @@ -317,6 +309,7 @@ namespace ArchiSteamFarm { } } + [SuppressMessage("ReSharper", "UnusedMember.Global")] internal sealed class TradeOfferRequest { internal sealed class ItemList { [JsonProperty(PropertyName = "assets", Required = Required.Always)] diff --git a/ArchiSteamFarm/Logging.cs b/ArchiSteamFarm/Logging.cs index 413970784..4ea10de6d 100644 --- a/ArchiSteamFarm/Logging.cs +++ b/ArchiSteamFarm/Logging.cs @@ -36,18 +36,20 @@ namespace ArchiSteamFarm { internal static void Init() { LogToFile = Program.GlobalConfig.LogToFile; - if (LogToFile) { - lock (FileLock) { - if (!LogToFile) { - return; - } + if (!LogToFile) { + return; + } - try { - File.Delete(Program.LogFile); - } catch (Exception e) { - LogToFile = false; - LogGenericException(e); - } + lock (FileLock) { + if (!LogToFile) { + return; + } + + try { + File.Delete(Program.LogFile); + } catch (Exception e) { + LogToFile = false; + LogGenericException(e); } } } @@ -69,15 +71,20 @@ namespace ArchiSteamFarm { } internal static void LogGenericException(Exception exception, string botName = "Main", [CallerMemberName] string previousMethodName = null) { - if (exception == null) { - return; - } + while (true) { + if (exception == null) { + return; + } - Log("[!] EXCEPTION: " + previousMethodName + "() <" + botName + "> " + exception.Message); - Log("[!] StackTrace:" + Environment.NewLine + exception.StackTrace); + Log("[!] EXCEPTION: " + previousMethodName + "() <" + botName + "> " + exception.Message); + Log("[!] StackTrace:" + Environment.NewLine + exception.StackTrace); - if (exception.InnerException != null) { - LogGenericException(exception.InnerException, botName, previousMethodName); + if (exception.InnerException != null) { + exception = exception.InnerException; + continue; + } + + break; } } @@ -102,9 +109,11 @@ namespace ArchiSteamFarm { return; } + // ReSharper disable once ExplicitCallerInfoArgument LogGenericError(nullObjectName + " is null!", botName, previousMethodName); } + // ReSharper disable once UnusedMember.Global [Conditional("DEBUG")] internal static void LogGenericDebug(string message, string botName = "Main", [CallerMemberName] string previousMethodName = null) { if (string.IsNullOrEmpty(message)) { @@ -125,21 +134,26 @@ namespace ArchiSteamFarm { if (!Program.ConsoleIsBusy) { try { Console.Write(loggedMessage); - } catch { } + } + catch { + // Ignored + } } - if (LogToFile) { - lock (FileLock) { - if (!LogToFile) { - return; - } + if (!LogToFile) { + return; + } - try { - File.AppendAllText(Program.LogFile, loggedMessage); - } catch (Exception e) { - LogToFile = false; - LogGenericException(e); - } + lock (FileLock) { + if (!LogToFile) { + return; + } + + try { + File.AppendAllText(Program.LogFile, loggedMessage); + } catch (Exception e) { + LogToFile = false; + LogGenericException(e); } } } diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 93847a114..3c30ffb96 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -26,11 +26,13 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using ArchiSteamFarm.JSON; namespace ArchiSteamFarm { internal static class Program { @@ -49,21 +51,22 @@ namespace ArchiSteamFarm { } private enum EMode : byte { + [SuppressMessage("ReSharper", "UnusedMember.Local")] Unknown, Normal, // Standard most common usage Client, // WCF client only Server // Normal + WCF server } - internal const string ASF = "ASF"; internal const string ConfigDirectory = "config"; internal const string DebugDirectory = "debug"; internal const string LogFile = "log.txt"; internal const string GithubRepo = "JustArchi/ArchiSteamFarm"; - internal const string GlobalConfigFile = ASF + ".json"; - internal const string GlobalDatabaseFile = ASF + ".db"; + private const string ASF = "ASF"; private const string GithubReleaseURL = "https://api.github.com/repos/" + GithubRepo + "/releases"; // GitHub API is HTTPS only + private const string GlobalConfigFile = ASF + ".json"; + private const string GlobalDatabaseFile = ASF + ".db"; internal static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version; @@ -76,7 +79,7 @@ namespace ArchiSteamFarm { internal static GlobalConfig GlobalConfig { get; private set; } internal static GlobalDatabase GlobalDatabase { get; private set; } - internal static bool ConsoleIsBusy { get; private set; } = false; + internal static bool ConsoleIsBusy { get; private set; } private static Timer AutoUpdatesTimer; private static EMode Mode = EMode.Normal; @@ -109,7 +112,7 @@ namespace ArchiSteamFarm { string response = null; Logging.LogGenericInfo("Checking new version..."); - for (byte i = 0; i < WebBrowser.MaxRetries && string.IsNullOrEmpty(response); i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && string.IsNullOrEmpty(response); i++) { response = await WebBrowser.UrlGetToContent(releaseURL).ConfigureAwait(false); } @@ -135,7 +138,7 @@ namespace ArchiSteamFarm { return; } - if (releases == null || releases.Count == 0) { + if ((releases == null) || (releases.Count == 0)) { Logging.LogGenericWarning("Could not check latest version!"); return; } @@ -153,15 +156,19 @@ namespace ArchiSteamFarm { Logging.LogGenericInfo("Local version: " + Version + " | Remote version: " + newVersion); if (Version.CompareTo(newVersion) >= 0) { // If local version is the same or newer than remote version - if (AutoUpdatesTimer == null && GlobalConfig.AutoUpdates) { - Logging.LogGenericInfo("ASF will automatically check for new versions every 24 hours"); - AutoUpdatesTimer = new Timer( - async e => await CheckForUpdate().ConfigureAwait(false), - null, - TimeSpan.FromDays(1), // Delay - TimeSpan.FromDays(1) // Period - ); + if ((AutoUpdatesTimer != null) || !GlobalConfig.AutoUpdates) { + return; } + + Logging.LogGenericInfo("ASF will automatically check for new versions every 24 hours"); + + AutoUpdatesTimer = new Timer( + async e => await CheckForUpdate().ConfigureAwait(false), + null, + TimeSpan.FromDays(1), // Delay + TimeSpan.FromDays(1) // Period + ); + return; } @@ -183,15 +190,7 @@ namespace ArchiSteamFarm { return; } - GitHub.ReleaseResponse.Asset binaryAsset = null; - foreach (var asset in releaseResponse.Assets) { - if (string.IsNullOrEmpty(asset.Name) || !asset.Name.Equals(ExecutableName, StringComparison.OrdinalIgnoreCase)) { - continue; - } - - binaryAsset = asset; - break; - } + GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(ExecutableName, StringComparison.OrdinalIgnoreCase)); if (binaryAsset == null) { Logging.LogGenericWarning("Could not proceed with update because there is no asset that relates to currently running binary!"); @@ -204,7 +203,7 @@ namespace ArchiSteamFarm { } byte[] result = null; - for (byte i = 0; i < WebBrowser.MaxRetries && result == null; i++) { + for (byte i = 0; (i < WebBrowser.MaxRetries) && (result == null); i++) { Logging.LogGenericInfo("Downloading new version..."); result = await WebBrowser.UrlGetToBytes(binaryAsset.DownloadURL).ConfigureAwait(false); } @@ -232,7 +231,9 @@ namespace ArchiSteamFarm { try { // Cleanup File.Delete(newExeFile); - } catch { } + } catch { + // Ignored + } return; } @@ -245,7 +246,9 @@ namespace ArchiSteamFarm { // Cleanup File.Move(oldExeFile, ExecutableFile); File.Delete(newExeFile); - } catch { } + } catch { + // Ignored + } return; } @@ -326,6 +329,7 @@ namespace ArchiSteamFarm { Console.Write((string.IsNullOrEmpty(botName) ? "" : "<" + botName + "> ") + "Please enter not documented yet value of \"" + userInputType + "\": "); break; } + result = Console.ReadLine(); if (!Console.IsOutputRedirected) { Console.Clear(); // For security purposes @@ -337,10 +341,8 @@ namespace ArchiSteamFarm { } internal static void OnBotShutdown() { - foreach (Bot bot in Bot.Bots.Values) { - if (bot.KeepRunning) { - return; - } + if (Bot.Bots.Values.Any(bot => bot.KeepRunning)) { + return; } if (WCF.IsServerRunning()) { @@ -374,7 +376,11 @@ namespace ArchiSteamFarm { WebBrowser = new WebBrowser("Main"); } - private static void ParseArgs(string[] args) { + private static void ParseArgs(IEnumerable args) { + if (args == null) { + return; + } + foreach (string arg in args) { switch (arg) { case "--client": @@ -385,7 +391,7 @@ namespace ArchiSteamFarm { WCF.StartServer(); break; default: - if (arg.StartsWith("--")) { + if (arg.StartsWith("--", StringComparison.Ordinal)) { Logging.LogGenericWarning("Unrecognized parameter: " + arg); continue; } @@ -410,7 +416,7 @@ namespace ArchiSteamFarm { } private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) { - if (sender == null || args == null) { + if ((sender == null) || (args == null)) { return; } @@ -418,14 +424,14 @@ namespace ArchiSteamFarm { } private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) { - if (sender == null || args == null) { + if ((sender == null) || (args == null)) { return; } Logging.LogGenericException(args.Exception); } - private static void Init(string[] args) { + private static void Init(IEnumerable args) { AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler; TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler; @@ -437,7 +443,7 @@ namespace ArchiSteamFarm { if (Debugging.IsDebugBuild) { // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up - for (var i = 0; i < 4; i++) { + for (byte i = 0; i < 4; i++) { Directory.SetCurrentDirectory(".."); if (Directory.Exists(ConfigDirectory)) { break; @@ -458,7 +464,7 @@ namespace ArchiSteamFarm { } Directory.CreateDirectory(DebugDirectory); - SteamKit2.DebugLog.AddListener(new Debugging.DebugListener(Path.Combine(Program.DebugDirectory, "debug.txt"))); + SteamKit2.DebugLog.AddListener(new Debugging.DebugListener(Path.Combine(DebugDirectory, "debug.txt"))); SteamKit2.DebugLog.Enabled = true; } @@ -486,8 +492,7 @@ namespace ArchiSteamFarm { bool isRunning = false; - foreach (var configFile in Directory.EnumerateFiles(ConfigDirectory, "*.json")) { - string botName = Path.GetFileNameWithoutExtension(configFile); + foreach (string botName in Directory.EnumerateFiles(ConfigDirectory, "*.json").Select(Path.GetFileNameWithoutExtension)) { switch (botName) { case ASF: case "example": @@ -496,7 +501,7 @@ namespace ArchiSteamFarm { } Bot bot = new Bot(botName); - if (bot.BotConfig != null && bot.BotConfig.Enabled) { + if ((bot.BotConfig != null) && bot.BotConfig.Enabled) { if (bot.BotConfig.StartOnLaunch) { isRunning = true; } diff --git a/ArchiSteamFarm/Properties/AssemblyInfo.cs b/ArchiSteamFarm/Properties/AssemblyInfo.cs index bbdd93439..c0be8c9e5 100644 --- a/ArchiSteamFarm/Properties/AssemblyInfo.cs +++ b/ArchiSteamFarm/Properties/AssemblyInfo.cs @@ -1,8 +1,7 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("ArchiSteamFarm")] @@ -14,8 +13,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,11 +24,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.0.4.6")] diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index 44e61a233..74724def1 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -25,8 +25,10 @@ using SteamAuth; using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; +using ArchiSteamFarm.JSON; namespace ArchiSteamFarm { internal sealed class Trading { @@ -50,7 +52,7 @@ namespace ArchiSteamFarm { internal Trading(Bot bot) { if (bot == null) { - throw new ArgumentNullException("bot"); + throw new ArgumentNullException(nameof(bot)); } Bot = bot; @@ -77,7 +79,7 @@ namespace ArchiSteamFarm { private async Task ParseActiveTrades() { HashSet tradeOffers = Bot.ArchiWebHandler.GetTradeOffers(); - if (tradeOffers == null || tradeOffers.Count == 0) { + if ((tradeOffers == null) || (tradeOffers.Count == 0)) { return; } @@ -86,7 +88,7 @@ namespace ArchiSteamFarm { } private async Task ParseTrade(Steam.TradeOffer tradeOffer) { - if (tradeOffer == null || tradeOffer.State != Steam.TradeOffer.ETradeOfferState.Active) { + if ((tradeOffer == null) || (tradeOffer.State != Steam.TradeOffer.ETradeOfferState.Active)) { return; } @@ -110,7 +112,7 @@ namespace ArchiSteamFarm { } // Always accept trades from SteamMasterID - if (tradeOffer.OtherSteamID64 != 0 && tradeOffer.OtherSteamID64 == Bot.BotConfig.SteamMasterID) { + if ((tradeOffer.OtherSteamID64 != 0) && (tradeOffer.OtherSteamID64 == Bot.BotConfig.SteamMasterID)) { return true; } @@ -132,7 +134,7 @@ namespace ArchiSteamFarm { // At this point we're sure that STM trade is valid // Now check if it's worth for us to do the trade HashSet inventory = await Bot.ArchiWebHandler.GetMyTradableInventory().ConfigureAwait(false); - if (inventory == null || inventory.Count == 0) { + if ((inventory == null) || (inventory.Count == 0)) { return true; // OK, assume that this trade is valid, we can't check our EQ } @@ -166,9 +168,7 @@ namespace ArchiSteamFarm { // Calculate our value of items to give List amountsToGive = new List(tradeOffer.ItemsToGive.Count); - foreach (Steam.Item item in tradeOffer.ItemsToGive) { - Tuple key = new Tuple(item.ClassID, item.InstanceID); - + foreach (Tuple key in tradeOffer.ItemsToGive.Select(item => new Tuple(item.ClassID, item.InstanceID))) { uint amount; if (!amountMap.TryGetValue(key, out amount)) { amountsToGive.Add(0); @@ -183,9 +183,7 @@ namespace ArchiSteamFarm { // Calculate our value of items to receive List amountsToReceive = new List(tradeOffer.ItemsToReceive.Count); - foreach (Steam.Item item in tradeOffer.ItemsToReceive) { - Tuple key = new Tuple(item.ClassID, item.InstanceID); - + foreach (Tuple key in tradeOffer.ItemsToReceive.Select(item => new Tuple(item.ClassID, item.InstanceID))) { uint amount; if (!amountMap.TryGetValue(key, out amount)) { amountsToReceive.Add(0); @@ -199,10 +197,7 @@ namespace ArchiSteamFarm { amountsToReceive.Sort(); // Check actual difference - int difference = 0; - for (int i = 0; i < amountsToGive.Count; i++) { - difference += (int) (amountsToGive[i] - amountsToReceive[i]); - } + 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; diff --git a/ArchiSteamFarm/Utilities.cs b/ArchiSteamFarm/Utilities.cs index c352fd387..a783b550d 100644 --- a/ArchiSteamFarm/Utilities.cs +++ b/ArchiSteamFarm/Utilities.cs @@ -30,43 +30,20 @@ using System.Threading.Tasks; namespace ArchiSteamFarm { internal static class Utilities { + // ReSharper disable once UnusedParameter.Global internal static void Forget(this Task task) { } - internal static Task ForEachAsync(this IEnumerable sequence, Func action) { - if (action == null) { - return Task.FromResult(true); - } + internal static Task ForEachAsync(this IEnumerable sequence, Func action) => action == null ? Task.FromResult(true) : Task.WhenAll(sequence.Select(action)); - return Task.WhenAll(sequence.Select(action)); - } - - internal static string GetCookieValue(this CookieContainer cookieContainer, string URL, string name) { - if (string.IsNullOrEmpty(URL) || string.IsNullOrEmpty(name)) { + internal static string GetCookieValue(this CookieContainer cookieContainer, string url, string name) { + if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(name)) { return null; } - CookieCollection cookies = cookieContainer.GetCookies(new Uri(URL)); - if (cookies == null || cookies.Count == 0) { - return null; - } - - foreach (Cookie cookie in cookies) { - if (!cookie.Name.Equals(name, StringComparison.Ordinal)) { - continue; - } - - return cookie.Value; - } - - return null; + CookieCollection cookies = cookieContainer.GetCookies(new Uri(url)); + return cookies.Count == 0 ? null : (from Cookie cookie in cookies where cookie.Name.Equals(name, StringComparison.Ordinal) select cookie.Value).FirstOrDefault(); } - internal static Task SleepAsync(int miliseconds) { - if (miliseconds < 0) { - return Task.FromResult(true); - } - - return Task.Delay(miliseconds); - } + internal static Task SleepAsync(int miliseconds) => miliseconds < 0 ? Task.FromResult(true) : Task.Delay(miliseconds); } } diff --git a/ArchiSteamFarm/WCF.cs b/ArchiSteamFarm/WCF.cs index 315a9fe00..26bf3538e 100644 --- a/ArchiSteamFarm/WCF.cs +++ b/ArchiSteamFarm/WCF.cs @@ -52,9 +52,7 @@ namespace ArchiSteamFarm { URL = "http://" + Program.GlobalConfig.WCFHostname + ":" + Program.GlobalConfig.WCFPort + "/ASF"; } - internal bool IsServerRunning() { - return ServiceHost != null; - } + internal bool IsServerRunning() => ServiceHost != null; internal void StartServer() { if (ServiceHost != null) { diff --git a/ArchiSteamFarm/WebBrowser.cs b/ArchiSteamFarm/WebBrowser.cs index a914f3f83..8c7fa1e46 100644 --- a/ArchiSteamFarm/WebBrowser.cs +++ b/ArchiSteamFarm/WebBrowser.cs @@ -27,7 +27,6 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; -using System.IO; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -65,7 +64,7 @@ namespace ArchiSteamFarm { internal WebBrowser(string identifier) { if (string.IsNullOrEmpty(identifier)) { - throw new ArgumentNullException("identifier"); + throw new ArgumentNullException(nameof(identifier)); } Identifier = identifier; @@ -99,11 +98,7 @@ namespace ArchiSteamFarm { } using (HttpResponseMessage response = await UrlHeadToResponse(request, referer).ConfigureAwait(false)) { - if (response == null) { - return null; - } - - return response.RequestMessage.RequestUri; + return response == null ? null : response.RequestMessage.RequestUri; } } @@ -229,7 +224,7 @@ namespace ArchiSteamFarm { } private async Task UrlRequest(string request, HttpMethod httpMethod, Dictionary data = null, string referer = null) { - if (string.IsNullOrEmpty(request) || httpMethod == null) { + if (string.IsNullOrEmpty(request) || (httpMethod == null)) { return null; } @@ -239,7 +234,7 @@ namespace ArchiSteamFarm { HttpResponseMessage responseMessage; using (HttpRequestMessage requestMessage = new HttpRequestMessage(httpMethod, request)) { - if (data != null && data.Count > 0) { + if ((data != null) && (data.Count > 0)) { try { requestMessage.Content = new FormUrlEncodedContent(data); } catch (UriFormatException e) { @@ -263,17 +258,18 @@ namespace ArchiSteamFarm { return null; } - if (!responseMessage.IsSuccessStatusCode) { - if (Debugging.IsDebugBuild || Program.GlobalConfig.Debug) { - Logging.LogGenericError("Request: " + request + " failed!", Identifier); - Logging.LogGenericError("Status code: " + responseMessage.StatusCode, Identifier); - Logging.LogGenericError("Content: " + Environment.NewLine + await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false), Identifier); - } - responseMessage.Dispose(); - return null; + if (responseMessage.IsSuccessStatusCode) { + return responseMessage; } - return responseMessage; + if (Debugging.IsDebugBuild || Program.GlobalConfig.Debug) { + Logging.LogGenericError("Request: " + request + " failed!", Identifier); + Logging.LogGenericError("Status code: " + responseMessage.StatusCode, Identifier); + Logging.LogGenericError("Content: " + Environment.NewLine + await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false), Identifier); + } + + responseMessage.Dispose(); + return null; } } } diff --git a/ConfigGenerator/ASFConfig.cs b/ConfigGenerator/ASFConfig.cs index 18d5509f2..102b54588 100644 --- a/ConfigGenerator/ASFConfig.cs +++ b/ConfigGenerator/ASFConfig.cs @@ -39,13 +39,13 @@ namespace ConfigGenerator { protected ASFConfig(string filePath) : this() { if (string.IsNullOrEmpty(filePath)) { - throw new ArgumentNullException("filePath"); + throw new ArgumentNullException(nameof(filePath)); } FilePath = filePath; } - internal virtual void Save() { + internal void Save() { lock (FilePath) { try { File.WriteAllText(FilePath, JsonConvert.SerializeObject(this, Formatting.Indented)); @@ -55,7 +55,7 @@ namespace ConfigGenerator { } } - internal virtual void Remove() { + internal void Remove() { string queryPath = Path.GetFileNameWithoutExtension(FilePath); lock (FilePath) { foreach (string botFile in Directory.EnumerateFiles(Program.ConfigDirectory, queryPath + ".*")) { @@ -66,10 +66,11 @@ namespace ConfigGenerator { } } } + ASFConfigs.Remove(this); } - internal virtual void Rename(string botName) { + internal void Rename(string botName) { if (string.IsNullOrEmpty(botName)) { return; } @@ -83,6 +84,7 @@ namespace ConfigGenerator { Logging.LogGenericException(e); } } + FilePath = Path.Combine(Program.ConfigDirectory, botName + ".json"); } } diff --git a/ConfigGenerator/BotConfig.cs b/ConfigGenerator/BotConfig.cs index bd087e253..73b0f43a1 100644 --- a/ConfigGenerator/BotConfig.cs +++ b/ConfigGenerator/BotConfig.cs @@ -26,9 +26,11 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.IO; namespace ConfigGenerator { + [SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global"), SuppressMessage("ReSharper", "CollectionNeverQueried.Global"), SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnusedMember.Global")] internal sealed class BotConfig : ASFConfig { [JsonProperty(Required = Required.DisallowNull)] public bool Enabled { get; set; } = false; @@ -39,8 +41,7 @@ namespace ConfigGenerator { [JsonProperty] public string SteamLogin { get; set; } = null; - [JsonProperty] - [PasswordPropertyText(true)] + [JsonProperty, PasswordPropertyText(true)] public string SteamPassword { get; set; } = null; [JsonProperty] @@ -130,11 +131,12 @@ namespace ConfigGenerator { } // This constructor is used only by deserializer + // ReSharper disable once UnusedMember.Local private BotConfig() { } private BotConfig(string filePath) : base(filePath) { if (string.IsNullOrEmpty(filePath)) { - throw new ArgumentNullException("filePath"); + throw new ArgumentNullException(nameof(filePath)); } GamesPlayedWhileIdle.Add(0); diff --git a/ConfigGenerator/ConfigGenerator.csproj b/ConfigGenerator/ConfigGenerator.csproj index a778d1165..2ceb4f586 100644 --- a/ConfigGenerator/ConfigGenerator.csproj +++ b/ConfigGenerator/ConfigGenerator.csproj @@ -83,6 +83,7 @@ True Resources.resx + True diff --git a/ConfigGenerator/ConfigPage.cs b/ConfigGenerator/ConfigPage.cs index ae3a2cb83..8eabfa172 100644 --- a/ConfigGenerator/ConfigPage.cs +++ b/ConfigGenerator/ConfigPage.cs @@ -42,8 +42,6 @@ namespace ConfigGenerator { Controls.Add(enhancedPropertyGrid); } - internal void RefreshText() { - Text = Path.GetFileNameWithoutExtension(ASFConfig.FilePath); - } + internal void RefreshText() => Text = Path.GetFileNameWithoutExtension(ASFConfig.FilePath); } } diff --git a/ConfigGenerator/Debugging.cs b/ConfigGenerator/Debugging.cs index a67548b0e..f30883203 100644 --- a/ConfigGenerator/Debugging.cs +++ b/ConfigGenerator/Debugging.cs @@ -25,11 +25,11 @@ namespace ConfigGenerator { internal static class Debugging { #if DEBUG + // ReSharper disable once ConvertToConstant.Global internal static readonly bool IsDebugBuild = true; #else + // ReSharper disable once ConvertToConstant.Global internal static readonly bool IsDebugBuild = false; #endif - - internal static bool IsReleaseBuild => !IsDebugBuild; } } diff --git a/ConfigGenerator/DialogBox.cs b/ConfigGenerator/DialogBox.cs index 595b2489b..c8bc731c0 100644 --- a/ConfigGenerator/DialogBox.cs +++ b/ConfigGenerator/DialogBox.cs @@ -25,50 +25,53 @@ using System; using System.Drawing; using System.Windows.Forms; +using ConfigGenerator.Properties; namespace ConfigGenerator { - internal sealed class DialogBox { + internal static class DialogBox { internal static DialogResult InputBox(string title, string promptText, out string value) { if (string.IsNullOrEmpty(title) || string.IsNullOrEmpty(promptText)) { value = null; return DialogResult.Abort; } - Form form = new Form(); - Label label = new Label(); - TextBox textBox = new TextBox(); + TextBox textBox = new TextBox { + Anchor = AnchorStyles.Right, + Bounds = new Rectangle(12, 36, 372, 20), + Width = 1000 + }; - textBox.Width = 1000; - Button buttonOk = new Button(); - Button buttonCancel = new Button(); + Button buttonOk = new Button { + Anchor = AnchorStyles.Bottom | AnchorStyles.Right, + Bounds = new Rectangle(228, 72, 75, 23), + DialogResult = DialogResult.OK, + Text = Resources.OK + }; - form.Text = title; - label.Text = promptText; + Button buttonCancel = new Button { + Anchor = AnchorStyles.Bottom | AnchorStyles.Right, + Bounds = new Rectangle(309, 72, 75, 23), + DialogResult = DialogResult.Cancel, + Text = Resources.Cancel + }; - buttonOk.Text = "OK"; - buttonCancel.Text = "Cancel"; - buttonOk.DialogResult = DialogResult.OK; - buttonCancel.DialogResult = DialogResult.Cancel; + Label label = new Label { + AutoSize = true, + Bounds = new Rectangle(9, 20, 372, 13), + Text = promptText + }; - label.SetBounds(9, 20, 372, 13); - textBox.SetBounds(12, 36, 372, 20); - buttonOk.SetBounds(228, 72, 75, 23); - buttonCancel.SetBounds(309, 72, 75, 23); - - label.AutoSize = true; - textBox.Anchor = textBox.Anchor | AnchorStyles.Right; - buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - - form.ClientSize = new Size(396, 107); - form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel }); - form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height); - form.FormBorderStyle = FormBorderStyle.FixedDialog; - form.StartPosition = FormStartPosition.CenterScreen; - form.MinimizeBox = false; - form.MaximizeBox = false; - form.AcceptButton = buttonOk; - form.CancelButton = buttonCancel; + Form form = new Form { + AcceptButton = buttonOk, + CancelButton = buttonCancel, + ClientSize = new Size(Math.Max(300, label.Right + 10), 107), + Controls = { label, textBox, buttonOk, buttonCancel }, + FormBorderStyle = FormBorderStyle.FixedDialog, + MinimizeBox = false, + MaximizeBox = false, + StartPosition = FormStartPosition.CenterScreen, + Text = title + }; DialogResult dialogResult = form.ShowDialog(); value = textBox.Text; @@ -80,37 +83,37 @@ namespace ConfigGenerator { return DialogResult.Abort; } - Form form = new Form(); - Label label = new Label(); + Button buttonYes = new Button { + Anchor = AnchorStyles.Bottom | AnchorStyles.Right, + Bounds = new Rectangle(228, 72, 75, 23), + DialogResult = DialogResult.Yes, + Text = Resources.Yes + }; - Button buttonOk = new Button(); - Button buttonCancel = new Button(); + Button buttonNo = new Button { + Anchor = AnchorStyles.Bottom | AnchorStyles.Right, + Bounds = new Rectangle(309, 72, 75, 23), + DialogResult = DialogResult.No, + Text = Resources.No + }; - form.Text = title; - label.Text = promptText; + Label label = new Label { + AutoSize = true, + Bounds = new Rectangle(9, 20, 372, 13), + Text = promptText + }; - buttonOk.Text = "Yes"; - buttonCancel.Text = "No"; - buttonOk.DialogResult = DialogResult.Yes; - buttonCancel.DialogResult = DialogResult.No; - - label.SetBounds(9, 20, 372, 13); - buttonOk.SetBounds(228, 50, 75, 23); - buttonCancel.SetBounds(309, 50, 75, 23); - - label.AutoSize = true; - buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; - - form.ClientSize = new Size(396, 80); - form.Controls.AddRange(new Control[] { label, buttonOk, buttonCancel }); - form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height); - form.FormBorderStyle = FormBorderStyle.FixedDialog; - form.StartPosition = FormStartPosition.CenterScreen; - form.MinimizeBox = false; - form.MaximizeBox = false; - form.AcceptButton = buttonOk; - form.CancelButton = buttonCancel; + Form form = new Form { + AcceptButton = buttonYes, + CancelButton = buttonNo, + ClientSize = new Size(Math.Max(300, label.Right + 10), 107), + Controls = { label, buttonYes, buttonNo }, + FormBorderStyle = FormBorderStyle.FixedDialog, + MinimizeBox = false, + MaximizeBox = false, + StartPosition = FormStartPosition.CenterScreen, + Text = title + }; DialogResult dialogResult = form.ShowDialog(); return dialogResult; diff --git a/ConfigGenerator/EnhancedPropertyGrid.cs b/ConfigGenerator/EnhancedPropertyGrid.cs index e77f0cfb1..652dabbb7 100644 --- a/ConfigGenerator/EnhancedPropertyGrid.cs +++ b/ConfigGenerator/EnhancedPropertyGrid.cs @@ -31,7 +31,7 @@ namespace ConfigGenerator { internal EnhancedPropertyGrid(ASFConfig config) { if (config == null) { - throw new ArgumentNullException("config"); + throw new ArgumentNullException(nameof(config)); } ASFConfig = config; @@ -53,20 +53,24 @@ namespace ConfigGenerator { BotConfig botConfig = ASFConfig as BotConfig; if (botConfig != null) { - if (botConfig.Enabled) { - Tutorial.OnAction(Tutorial.EPhase.BotEnabled); - if (!string.IsNullOrEmpty(botConfig.SteamLogin) && !string.IsNullOrEmpty(botConfig.SteamPassword)) { - Tutorial.OnAction(Tutorial.EPhase.BotReady); - } + if (!botConfig.Enabled) { + return; + } + + Tutorial.OnAction(Tutorial.EPhase.BotEnabled); + if (!string.IsNullOrEmpty(botConfig.SteamLogin) && !string.IsNullOrEmpty(botConfig.SteamPassword)) { + Tutorial.OnAction(Tutorial.EPhase.BotReady); } return; } GlobalConfig globalConfig = ASFConfig as GlobalConfig; - if (globalConfig != null) { - if (globalConfig.SteamOwnerID != 0) { - Tutorial.OnAction(Tutorial.EPhase.GlobalConfigReady); - } + if (globalConfig == null) { + return; + } + + if (globalConfig.SteamOwnerID != 0) { + Tutorial.OnAction(Tutorial.EPhase.GlobalConfigReady); } } diff --git a/ConfigGenerator/GlobalConfig.cs b/ConfigGenerator/GlobalConfig.cs index cf63de575..a14962c32 100644 --- a/ConfigGenerator/GlobalConfig.cs +++ b/ConfigGenerator/GlobalConfig.cs @@ -25,11 +25,14 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Sockets; namespace ConfigGenerator { + [SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global"), SuppressMessage("ReSharper", "CollectionNeverQueried.Global"), SuppressMessage("ReSharper", "MemberCanBePrivate.Global"), SuppressMessage("ReSharper", "UnusedMember.Global")] internal sealed class GlobalConfig : ASFConfig { + [SuppressMessage("ReSharper", "UnusedMember.Global")] internal enum EUpdateChannel : byte { Unknown, Stable, @@ -43,7 +46,7 @@ namespace ConfigGenerator { private const ProtocolType DefaultSteamProtocol = ProtocolType.Tcp; // This is hardcoded blacklist which should not be possible to change - internal static readonly HashSet GlobalBlacklist = new HashSet { 267420, 303700, 335590, 368020, 425280 }; + private static readonly HashSet GlobalBlacklist = new HashSet { 267420, 303700, 335590, 368020, 425280 }; [JsonProperty(Required = Required.DisallowNull)] public bool Debug { get; set; } = false; @@ -102,7 +105,6 @@ namespace ConfigGenerator { [JsonProperty(Required = Required.DisallowNull)] public bool Statistics { get; set; } = true; - // TODO: Please remove me immediately after https://github.com/SteamRE/SteamKit/issues/254 gets fixed [JsonProperty(Required = Required.DisallowNull)] public bool HackIgnoreMachineID { get; set; } = false; @@ -161,20 +163,22 @@ namespace ConfigGenerator { globalConfig.HttpTimeout = DefaultHttpTimeout; } - if (globalConfig.WCFPort == 0) { - Logging.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort + ". Value of " + DefaultWCFPort + " will be used instead"); - globalConfig.WCFPort = DefaultWCFPort; + if (globalConfig.WCFPort != 0) { + return globalConfig; } + Logging.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort + ". Value of " + DefaultWCFPort + " will be used instead"); + globalConfig.WCFPort = DefaultWCFPort; + return globalConfig; } - // This constructor is used only by deserializer + // ReSharper disable once UnusedMember.Local private GlobalConfig() { } private GlobalConfig(string filePath) : base(filePath) { if (string.IsNullOrEmpty(filePath)) { - throw new ArgumentNullException("filePath"); + throw new ArgumentNullException(nameof(filePath)); } Blacklist.AddRange(GlobalBlacklist); diff --git a/ConfigGenerator/Logging.cs b/ConfigGenerator/Logging.cs index 707b4a456..d602c5505 100644 --- a/ConfigGenerator/Logging.cs +++ b/ConfigGenerator/Logging.cs @@ -23,9 +23,9 @@ */ using System; -using System.Diagnostics; using System.Runtime.CompilerServices; using System.Windows.Forms; +using ConfigGenerator.Properties; namespace ConfigGenerator { internal static class Logging { @@ -34,15 +34,7 @@ namespace ConfigGenerator { return; } - MessageBox.Show(message, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - internal static void LogGenericWTF(string message, [CallerMemberName] string previousMethodName = "") { - if (string.IsNullOrEmpty(message)) { - return; - } - - MessageBox.Show(previousMethodName + "() " + message, "WTF", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(message, Resources.Information, MessageBoxButtons.OK, MessageBoxIcon.Information); } internal static void LogGenericError(string message, [CallerMemberName] string previousMethodName = "") { @@ -50,18 +42,23 @@ namespace ConfigGenerator { return; } - MessageBox.Show(previousMethodName + "() " + message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(previousMethodName + @"() " + message, Resources.Error, MessageBoxButtons.OK, MessageBoxIcon.Error); } internal static void LogGenericException(Exception exception, [CallerMemberName] string previousMethodName = "") { - if (exception == null) { - return; - } + while (true) { + if (exception == null) { + return; + } - MessageBox.Show(previousMethodName + "() " + exception.Message + Environment.NewLine + exception.StackTrace, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show(previousMethodName + @"() " + exception.Message + Environment.NewLine + exception.StackTrace, Resources.Exception, MessageBoxButtons.OK, MessageBoxIcon.Error); - if (exception.InnerException != null) { - LogGenericException(exception.InnerException, previousMethodName); + if (exception.InnerException != null) { + exception = exception.InnerException; + continue; + } + + break; } } @@ -70,24 +67,7 @@ namespace ConfigGenerator { return; } - MessageBox.Show(previousMethodName + "() " + message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - - internal static void LogNullError(string nullObjectName, [CallerMemberName] string previousMethodName = "") { - if (string.IsNullOrEmpty(nullObjectName)) { - return; - } - - LogGenericError(nullObjectName + " is null!", previousMethodName); - } - - [Conditional("DEBUG")] - internal static void LogGenericDebug(string message, [CallerMemberName] string previousMethodName = "") { - if (string.IsNullOrEmpty(message)) { - return; - } - - MessageBox.Show(previousMethodName + "() " + message, "Debug", MessageBoxButtons.OK, MessageBoxIcon.Information); + MessageBox.Show(previousMethodName + @"() " + message, Resources.Warning, MessageBoxButtons.OK, MessageBoxIcon.Warning); } } } diff --git a/ConfigGenerator/MainForm.cs b/ConfigGenerator/MainForm.cs index 66696f997..61f1bd8d7 100644 --- a/ConfigGenerator/MainForm.cs +++ b/ConfigGenerator/MainForm.cs @@ -26,6 +26,7 @@ using System; using System.ComponentModel; using System.Diagnostics; using System.IO; +using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; @@ -33,9 +34,9 @@ namespace ConfigGenerator { internal sealed partial class MainForm : Form { private const byte ReservedTabs = 3; - private readonly TabPage NewTab = new TabPage { Text = "+" }; - private readonly TabPage RemoveTab = new TabPage { Text = "-" }; - private readonly TabPage RenameTab = new TabPage { Text = "~" }; + private readonly TabPage NewTab = new TabPage { Text = @"+" }; + private readonly TabPage RemoveTab = new TabPage { Text = @"-" }; + private readonly TabPage RenameTab = new TabPage { Text = @"~" }; private ConfigPage ASFTab; private TabPage OldTab; @@ -45,7 +46,7 @@ namespace ConfigGenerator { } private void MainForm_Load(object sender, EventArgs e) { - if (sender == null || e == null) { + if ((sender == null) || (e == null)) { return; } @@ -53,7 +54,7 @@ namespace ConfigGenerator { MainTab.TabPages.Add(ASFTab); - foreach (var configFile in Directory.EnumerateFiles(Program.ConfigDirectory, "*.json")) { + foreach (string configFile in Directory.EnumerateFiles(Program.ConfigDirectory, "*.json")) { string botName = Path.GetFileNameWithoutExtension(configFile); switch (botName) { case Program.ASF: @@ -71,7 +72,7 @@ namespace ConfigGenerator { } private void MainTab_Selected(object sender, TabControlEventArgs e) { - if (sender == null || e == null) { + if ((sender == null) || (e == null)) { return; } @@ -151,11 +152,9 @@ namespace ConfigGenerator { // Get rid of any potential whitespaces in bot name input = Regex.Replace(input, @"\s+", ""); - foreach (ASFConfig config in ASFConfig.ASFConfigs) { - if (Path.GetFileNameWithoutExtension(config.FilePath).Equals(input)) { - Logging.LogGenericError("Bot with such name exists already!"); - return; - } + if (ASFConfig.ASFConfigs.Select(config => Path.GetFileNameWithoutExtension(config.FilePath)).Any(fileNameWithoutExtension => (fileNameWithoutExtension == null) || fileNameWithoutExtension.Equals(input))) { + Logging.LogGenericError("Bot with such name exists already!"); + return; } input = Path.Combine(Program.ConfigDirectory, input + ".json"); @@ -170,7 +169,7 @@ namespace ConfigGenerator { } private void MainTab_Deselecting(object sender, TabControlCancelEventArgs e) { - if (sender == null || e == null) { + if ((sender == null) || (e == null)) { return; } @@ -178,7 +177,7 @@ namespace ConfigGenerator { } private void MainForm_Shown(object sender, EventArgs e) { - if (sender == null || e == null) { + if ((sender == null) || (e == null)) { return; } @@ -186,7 +185,7 @@ namespace ConfigGenerator { } private void MainForm_HelpButtonClicked(object sender, CancelEventArgs e) { - if (sender == null || e == null) { + if ((sender == null) || (e == null)) { return; } diff --git a/ConfigGenerator/Program.cs b/ConfigGenerator/Program.cs index 8b9e0b83d..f7ac45408 100644 --- a/ConfigGenerator/Program.cs +++ b/ConfigGenerator/Program.cs @@ -61,10 +61,12 @@ namespace ConfigGenerator { // Common structure is bin/(x64/)Debug/ArchiSteamFarm.exe, so we allow up to 4 directories up for (byte i = 0; i < 4; i++) { Directory.SetCurrentDirectory(".."); - if (Directory.Exists(ASFDirectory)) { - Directory.SetCurrentDirectory(ASFDirectory); - break; + if (!Directory.Exists(ASFDirectory)) { + continue; } + + Directory.SetCurrentDirectory(ASFDirectory); + break; } // If config directory doesn't exist after our adjustment, abort all of that @@ -73,14 +75,16 @@ namespace ConfigGenerator { } } - if (!Directory.Exists(ConfigDirectory)) { - Logging.LogGenericError("Config directory could not be found!"); - Environment.Exit(1); + if (Directory.Exists(ConfigDirectory)) { + return; } + + Logging.LogGenericError("Config directory could not be found!"); + Environment.Exit(1); } private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) { - if (sender == null || args == null) { + if ((sender == null) || (args == null)) { return; } @@ -88,7 +92,7 @@ namespace ConfigGenerator { } private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) { - if (sender == null || args == null) { + if ((sender == null) || (args == null)) { return; } diff --git a/ConfigGenerator/Properties/AssemblyInfo.cs b/ConfigGenerator/Properties/AssemblyInfo.cs index 44495eb20..b59143d9f 100644 --- a/ConfigGenerator/Properties/AssemblyInfo.cs +++ b/ConfigGenerator/Properties/AssemblyInfo.cs @@ -1,8 +1,7 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("ConfigGenerator")] @@ -14,8 +13,8 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] @@ -25,11 +24,11 @@ using System.Runtime.InteropServices; // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Build and Revision Numbers +// You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/ConfigGenerator/Properties/Resources.Designer.cs b/ConfigGenerator/Properties/Resources.Designer.cs index b27842b2b..66a8c17b0 100644 --- a/ConfigGenerator/Properties/Resources.Designer.cs +++ b/ConfigGenerator/Properties/Resources.Designer.cs @@ -9,54 +9,127 @@ //------------------------------------------------------------------------------ namespace ConfigGenerator.Properties { - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if ((resourceMan == null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ConfigGenerator.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - } + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ConfigGenerator.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Cancel. + /// + internal static string Cancel { + get { + return ResourceManager.GetString("Cancel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Error. + /// + internal static string Error { + get { + return ResourceManager.GetString("Error", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception. + /// + internal static string Exception { + get { + return ResourceManager.GetString("Exception", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Information. + /// + internal static string Information { + get { + return ResourceManager.GetString("Information", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No. + /// + internal static string No { + get { + return ResourceManager.GetString("No", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to OK. + /// + internal static string OK { + get { + return ResourceManager.GetString("OK", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warning. + /// + internal static string Warning { + get { + return ResourceManager.GetString("Warning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Yes. + /// + internal static string Yes { + get { + return ResourceManager.GetString("Yes", resourceCulture); + } + } + } } diff --git a/ConfigGenerator/Properties/Resources.resx b/ConfigGenerator/Properties/Resources.resx index af7dbebba..77c0cb423 100644 --- a/ConfigGenerator/Properties/Resources.resx +++ b/ConfigGenerator/Properties/Resources.resx @@ -114,4 +114,28 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Information + + + Error + + + Exception + + + Warning + + + OK + + + Cancel + + + Yes + + + No + \ No newline at end of file diff --git a/ConfigGenerator/Tutorial.cs b/ConfigGenerator/Tutorial.cs index d837db379..caa15368b 100644 --- a/ConfigGenerator/Tutorial.cs +++ b/ConfigGenerator/Tutorial.cs @@ -38,12 +38,12 @@ namespace ConfigGenerator { GlobalConfigReady } - internal static bool Enabled { get; set; } = true; + internal static bool Enabled { private get; set; } = true; private static EPhase NextPhase = EPhase.Start; internal static void OnAction(EPhase phase) { - if (!Enabled || phase != NextPhase) { + if (!Enabled || (phase != NextPhase)) { return; }