From 3481adb3c56d808c689d6039b8c3f6e513167b5d Mon Sep 17 00:00:00 2001 From: JustArchi Date: Sun, 6 Mar 2016 02:20:41 +0100 Subject: [PATCH] ASF: Big revolution #131 --- .gitignore | 4 +- ArchiSteamFarm/ArchiSteamFarm.csproj | 21 +- ArchiSteamFarm/ArchiWebHandler.cs | 15 +- ArchiSteamFarm/Bot.cs | 383 +++++++--------------- ArchiSteamFarm/BotConfig.cs | 252 ++++++++++++++ ArchiSteamFarm/BotDatabase.cs | 96 ++++++ ArchiSteamFarm/CardsFarmer.cs | 6 +- ArchiSteamFarm/Program.cs | 15 +- ArchiSteamFarm/Properties/AssemblyInfo.cs | 4 +- ArchiSteamFarm/Trading.cs | 2 +- ArchiSteamFarm/config/example.json | 24 ++ ArchiSteamFarm/config/example.xml | 159 --------- ArchiSteamFarm/config/minimal.json | 24 ++ ArchiSteamFarm/config/minimal.xml | 9 - 14 files changed, 555 insertions(+), 459 deletions(-) create mode 100644 ArchiSteamFarm/BotConfig.cs create mode 100644 ArchiSteamFarm/BotDatabase.cs create mode 100644 ArchiSteamFarm/config/example.json delete mode 100755 ArchiSteamFarm/config/example.xml create mode 100644 ArchiSteamFarm/config/minimal.json delete mode 100644 ArchiSteamFarm/config/minimal.xml diff --git a/.gitignore b/.gitignore index 307b68247..7cf4a78ee 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,8 @@ # Ignore all config files, apart from ones we want to include ArchiSteamFarm/config/* -!ArchiSteamFarm/config/example.xml -!ArchiSteamFarm/config/minimal.xml +!ArchiSteamFarm/config/example.json +!ArchiSteamFarm/config/minimal.json # Ignore local debugging log file ArchiSteamFarm/log.txt diff --git a/ArchiSteamFarm/ArchiSteamFarm.csproj b/ArchiSteamFarm/ArchiSteamFarm.csproj index 1fcd4fd74..60835faec 100644 --- a/ArchiSteamFarm/ArchiSteamFarm.csproj +++ b/ArchiSteamFarm/ArchiSteamFarm.csproj @@ -36,7 +36,7 @@ bin\Debug\ DEBUG;TRACE prompt - 4 + 3 AnyCPU @@ -101,6 +101,8 @@ + + @@ -134,12 +136,6 @@ - - PreserveNewest - - - PreserveNewest - @@ -147,6 +143,9 @@ SteamAuth + + + @@ -155,15 +154,15 @@ mkdir "$(TargetDir)out" "$(TargetDir)out\config" - copy "$(TargetDir)config\example.xml" "$(TargetDir)out\config" - copy "$(TargetDir)config\minimal.xml" "$(TargetDir)out\config" + copy "$(TargetDir)config\example.json" "$(TargetDir)out\config" + copy "$(TargetDir)config\minimal.json" "$(TargetDir)out\config" "$(SolutionDir)tools\ILRepack.exe" /ndebug /internalize /parallel /targetplatform:v4 /wildcards /out:"$(TargetDir)out\ASF.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" del "$(TargetDir)out\ASF.exe.config" mkdir -p "$(TargetDir)out" "$(TargetDir)out/config" - cp "$(TargetDir)config/example.xml" "$(TargetDir)out/config" - cp "$(TargetDir)config/minimal.xml" "$(TargetDir)out/config" + cp "$(TargetDir)config/example.json" "$(TargetDir)out/config" + cp "$(TargetDir)config/minimal.json" "$(TargetDir)out/config" mono -O=all "$(SolutionDir)tools/ILRepack.exe" /ndebug /internalize /parallel /targetplatform:v4 /wildcards /out:"$(TargetDir)out/ASF.exe" "$(TargetDir)$(TargetName).exe" "$(TargetDir)*.dll" rm "$(TargetDir)out/ASF.exe.config" diff --git a/ArchiSteamFarm/ArchiWebHandler.cs b/ArchiSteamFarm/ArchiWebHandler.cs index a42c1d101..f498a113b 100644 --- a/ArchiSteamFarm/ArchiWebHandler.cs +++ b/ArchiSteamFarm/ArchiWebHandler.cs @@ -37,17 +37,12 @@ namespace ArchiSteamFarm { private const int Timeout = 1000 * WebBrowser.HttpTimeout; // In miliseconds private readonly Bot Bot; - private readonly string ApiKey; private readonly Dictionary Cookie = new Dictionary(4); private ulong SteamID; - internal ArchiWebHandler(Bot bot, string apiKey) { + internal ArchiWebHandler(Bot bot) { Bot = bot; - - if (!string.IsNullOrEmpty(apiKey) && !apiKey.Equals("null")) { - ApiKey = apiKey; - } } internal async Task Init(SteamClient steamClient, string webAPIUserNonce, string parentalPin) { @@ -147,12 +142,12 @@ namespace ArchiSteamFarm { } internal List GetTradeOffers() { - if (ApiKey == null) { + if (string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) { return null; } KeyValue response = null; - using (dynamic iEconService = WebAPI.GetInterface("IEconService", ApiKey)) { + using (dynamic iEconService = WebAPI.GetInterface("IEconService", Bot.BotConfig.SteamApiKey)) { iEconService.Timeout = Timeout; for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) { @@ -269,12 +264,12 @@ namespace ArchiSteamFarm { } internal bool DeclineTradeOffer(ulong tradeID) { - if (tradeID == 0 || ApiKey == null) { + if (tradeID == 0 || string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) { return false; } KeyValue response = null; - using (dynamic iEconService = WebAPI.GetInterface("IEconService", ApiKey)) { + using (dynamic iEconService = WebAPI.GetInterface("IEconService", Bot.BotConfig.SteamApiKey)) { iEconService.Timeout = Timeout; for (byte i = 0; i < WebBrowser.MaxRetries && response == null; i++) { diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index cae3b189c..981d6967f 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -33,7 +33,6 @@ using System.IO; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; -using System.Xml; using System.Text; namespace ArchiSteamFarm { @@ -42,16 +41,17 @@ namespace ArchiSteamFarm { private const ushort CallbackSleep = 500; // In miliseconds internal static readonly ConcurrentDictionary Bots = new ConcurrentDictionary(); - internal static readonly HashSet GlobalBlacklist = new HashSet { 303700, 335590, 368020, 425280 }; private static readonly uint LoginID = MsgClientLogon.ObfuscationMask; // This must be the same for all ASF bots and all ASF processes - private readonly string ConfigFile, LoginKeyFile, MobileAuthenticatorFile, SentryFile; + private readonly string SentryFile; private readonly Timer SendItemsTimer; internal readonly string BotName; internal readonly ArchiHandler ArchiHandler; internal readonly ArchiWebHandler ArchiWebHandler; + internal readonly BotConfig BotConfig; + internal readonly BotDatabase BotDatabase; internal readonly SteamClient SteamClient; private readonly CallbackManager CallbackManager; @@ -62,35 +62,10 @@ namespace ArchiSteamFarm { private readonly Trading Trading; internal bool KeepRunning { get; private set; } = false; - internal SteamGuardAccount SteamGuardAccount { get; private set; } - - // Config variables - internal bool Enabled { get; private set; } = false; - internal string SteamLogin { get; private set; } = "null"; - internal string SteamPassword { get; private set; } = "null"; - internal string SteamNickname { get; private set; } = "null"; - internal string SteamApiKey { get; private set; } = "null"; - internal string SteamParentalPIN { get; private set; } = "0"; - internal ulong SteamMasterID { get; private set; } = 0; - internal ulong SteamMasterClanID { get; private set; } = 0; - internal bool StartOnLaunch { get; private set; } = true; - internal bool CardDropsRestricted { get; private set; } = false; - internal bool FarmOffline { get; private set; } = false; - internal bool HandleOfflineMessages { get; private set; } = false; - internal bool ForwardKeysToOtherBots { get; private set; } = false; - internal bool DistributeKeys { get; private set; } = false; - internal bool UseAsfAsMobileAuthenticator { get; private set; } = false; - internal bool ShutdownOnFarmingFinished { get; private set; } = false; - internal bool SendOnFarmingFinished { get; private set; } = false; - internal string SteamTradeToken { get; private set; } = "null"; - internal byte SendTradePeriod { get; private set; } = 0; - internal HashSet Blacklist { get; } = new HashSet(); - internal HashSet GamesPlayedWhileIdle { get; } = new HashSet() { 0 }; - internal bool Statistics { get; private set; } = true; private bool InvalidPassword = false; private bool LoggedInElsewhere = false; - private string AuthCode, LoginKey, TwoFactorAuth; + private string AuthCode, TwoFactorAuth; internal static string GetAnyBotName() { foreach (string botName in Bots.Keys) { @@ -136,22 +111,6 @@ namespace ArchiSteamFarm { return; } - BotName = botName; - - string botPath = Path.Combine(Program.ConfigDirectory, botName); - ConfigFile = botPath + ".xml"; - LoginKeyFile = botPath + ".key"; - MobileAuthenticatorFile = botPath + ".auth"; - SentryFile = botPath + ".bin"; - - if (!ReadConfig()) { - return; - } - - if (!Enabled) { - return; - } - bool alreadyExists; lock (Bots) { alreadyExists = Bots.ContainsKey(botName); @@ -164,6 +123,62 @@ namespace ArchiSteamFarm { return; } + BotName = botName; + + string botPath = Path.Combine(Program.ConfigDirectory, botName); + + // CONVERSION START + if (File.Exists(botPath + ".xml")) { + BotConfig = BotConfig.LoadOldFormat(botPath + ".xml"); + if (BotConfig == null) { + return; + } + + if (BotConfig.Convert(botPath + ".json")) { + try { + File.Delete(botPath + ".xml"); + } catch (Exception e) { + Logging.LogGenericException(e, botName); + return; + } + } + } + // CONVERSION END + + BotConfig = BotConfig.Load(botPath + ".json"); + if (BotConfig == null) { + Logging.LogGenericError("Your config for this bot instance is invalid, it won't run!", botName); + return; + } + + // CONVERSION START + if (File.Exists(botPath + ".key")) { + BotDatabase = BotDatabase.Load(botPath + ".db"); + try { + BotDatabase.LoginKey = File.ReadAllText(botPath + ".key"); + File.Delete(botPath + ".key"); + } catch (Exception e) { + Logging.LogGenericException(e, BotName); + } + } + if (File.Exists(botPath + ".auth")) { + BotDatabase = BotDatabase.Load(botPath + ".db"); + try { + BotDatabase.SteamGuardAccount = JsonConvert.DeserializeObject(File.ReadAllText(botPath + ".auth")); + File.Delete(botPath + ".auth"); + } catch (Exception e) { + Logging.LogGenericException(e, BotName); + } + } + // CONVERSION END + + if (!BotConfig.Enabled) { + return; + } + + BotDatabase = BotDatabase.Load(botPath + ".db"); + SentryFile = botPath + ".bin"; + // Initialize SteamClient = new SteamClient(); @@ -184,14 +199,6 @@ namespace ArchiSteamFarm { CallbackManager.Subscribe(OnFriendMsg); CallbackManager.Subscribe(OnFriendMsgHistory); - if (UseAsfAsMobileAuthenticator && File.Exists(MobileAuthenticatorFile)) { - try { - SteamGuardAccount = JsonConvert.DeserializeObject(File.ReadAllText(MobileAuthenticatorFile)); - } catch (Exception e) { - Logging.LogGenericException(e, botName); - } - } - SteamUser = SteamClient.GetHandler(); CallbackManager.Subscribe(OnAccountInfo); CallbackManager.Subscribe(OnLoggedOff); @@ -203,20 +210,20 @@ namespace ArchiSteamFarm { CallbackManager.Subscribe(OnOfflineMessage); CallbackManager.Subscribe(OnPurchaseResponse); - ArchiWebHandler = new ArchiWebHandler(this, SteamApiKey); + ArchiWebHandler = new ArchiWebHandler(this); CardsFarmer = new CardsFarmer(this); Trading = new Trading(this); - if (SendTradePeriod > 0 && SendItemsTimer == null) { + if (BotConfig.SendTradePeriod > 0 && SendItemsTimer == null) { SendItemsTimer = new Timer( async e => await ResponseSendTrade().ConfigureAwait(false), null, - TimeSpan.FromHours(SendTradePeriod), // Delay - TimeSpan.FromHours(SendTradePeriod) // Period + TimeSpan.FromHours(BotConfig.SendTradePeriod), // Delay + TimeSpan.FromHours(BotConfig.SendTradePeriod) // Period ); } - if (!StartOnLaunch) { + if (!BotConfig.StartOnLaunch) { return; } @@ -225,15 +232,15 @@ namespace ArchiSteamFarm { } internal async Task AcceptAllConfirmations() { - if (SteamGuardAccount == null) { + if (BotDatabase.SteamGuardAccount == null) { return; } - await SteamGuardAccount.RefreshSessionAsync().ConfigureAwait(false); + await BotDatabase.SteamGuardAccount.RefreshSessionAsync().ConfigureAwait(false); try { - foreach (Confirmation confirmation in await SteamGuardAccount.FetchConfirmationsAsync().ConfigureAwait(false)) { - if (SteamGuardAccount.AcceptConfirmation(confirmation)) { + foreach (Confirmation confirmation in await BotDatabase.SteamGuardAccount.FetchConfirmationsAsync().ConfigureAwait(false)) { + if (BotDatabase.SteamGuardAccount.AcceptConfirmation(confirmation)) { Logging.LogGenericInfo("Accepting confirmation: Success!", BotName); } else { Logging.LogGenericWarning("Accepting confirmation: Failed!", BotName); @@ -247,10 +254,10 @@ namespace ArchiSteamFarm { } internal void ResetGamesPlayed() { - if (GamesPlayedWhileIdle.Contains(0)) { + if (BotConfig.GamesPlayedWhileIdle.Contains(0)) { ArchiHandler.PlayGames(0); } else { - ArchiHandler.PlayGames(GamesPlayedWhileIdle); + ArchiHandler.PlayGames(BotConfig.GamesPlayedWhileIdle); } } @@ -261,10 +268,10 @@ namespace ArchiSteamFarm { } internal async Task OnFarmingFinished(bool farmedSomething) { - if (farmedSomething && SendOnFarmingFinished) { + if (farmedSomething && BotConfig.SendOnFarmingFinished) { await ResponseSendTrade().ConfigureAwait(false); } - if (ShutdownOnFarmingFinished) { + if (BotConfig.ShutdownOnFarmingFinished) { Shutdown(); } } @@ -417,13 +424,13 @@ namespace ArchiSteamFarm { } private async Task ResponseSendTrade() { - if (SteamMasterID == 0) { + if (BotConfig.SteamMasterID == 0) { return "Trade couldn't be send because SteamMasterID is not defined!"; } string token = null; - if (!string.IsNullOrEmpty(SteamTradeToken) && !SteamTradeToken.Equals("null")) { - token = SteamTradeToken; + if (!string.IsNullOrEmpty(BotConfig.SteamTradeToken) && !BotConfig.SteamTradeToken.Equals("null")) { + token = BotConfig.SteamTradeToken; } await Trading.LimitInventoryRequestsAsync().ConfigureAwait(false); @@ -433,7 +440,7 @@ namespace ArchiSteamFarm { return "Nothing to send, inventory seems empty!"; } - if (await ArchiWebHandler.SendTradeOffer(inventory, SteamMasterID, token).ConfigureAwait(false)) { + if (await ArchiWebHandler.SendTradeOffer(inventory, BotConfig.SteamMasterID, token).ConfigureAwait(false)) { await AcceptAllConfirmations().ConfigureAwait(false); return "Trade offer sent successfully!"; } else { @@ -455,12 +462,12 @@ namespace ArchiSteamFarm { } private string Response2FA() { - if (SteamGuardAccount == null) { + if (BotDatabase.SteamGuardAccount == null) { return "That bot doesn't have ASF 2FA enabled!"; } long timeLeft = 30 - TimeAligner.GetSteamTime() % 30; - return "2FA Token: " + SteamGuardAccount.GenerateSteamGuardCode() + " (expires in " + timeLeft + " seconds)"; + return "2FA Token: " + BotDatabase.SteamGuardAccount.GenerateSteamGuardCode() + " (expires in " + timeLeft + " seconds)"; } private static string Response2FA(string botName) { @@ -477,7 +484,7 @@ namespace ArchiSteamFarm { } private string Response2FAOff() { - if (SteamGuardAccount == null) { + if (BotDatabase.SteamGuardAccount == null) { return "That bot doesn't have ASF 2FA enabled!"; } @@ -542,7 +549,7 @@ namespace ArchiSteamFarm { case ArchiHandler.PurchaseResponseCallback.EPurchaseResult.OnCooldown: case ArchiHandler.PurchaseResponseCallback.EPurchaseResult.RegionLocked: response.Append(Environment.NewLine + "<" + currentBot.BotName + "> Key: " + key + " | Status: " + purchaseResult + " | Items: " + string.Join("", items)); - if (DistributeKeys) { + if (BotConfig.DistributeKeys) { do { if (iterator.MoveNext()) { currentBot = iterator.Current; @@ -551,13 +558,13 @@ namespace ArchiSteamFarm { } } while (currentBot == this); - if (!ForwardKeysToOtherBots) { + if (!BotConfig.ForwardKeysToOtherBots) { key = reader.ReadLine(); } break; } - if (!ForwardKeysToOtherBots) { + if (!BotConfig.ForwardKeysToOtherBots) { key = reader.ReadLine(); break; } @@ -606,7 +613,7 @@ namespace ArchiSteamFarm { break; case ArchiHandler.PurchaseResponseCallback.EPurchaseResult.OK: response.Append(Environment.NewLine + "<" + currentBot.BotName + "> Key: " + key + " | Status: " + purchaseResult + " | Items: " + string.Join("", items)); - if (DistributeKeys) { + if (BotConfig.DistributeKeys) { do { if (iterator.MoveNext()) { currentBot = iterator.Current; @@ -620,7 +627,7 @@ namespace ArchiSteamFarm { case ArchiHandler.PurchaseResponseCallback.EPurchaseResult.DuplicatedKey: case ArchiHandler.PurchaseResponseCallback.EPurchaseResult.InvalidKey: response.Append(Environment.NewLine + "<" + currentBot.BotName + "> Key: " + key + " | Status: " + purchaseResult + " | Items: " + string.Join("", items)); - if (DistributeKeys && !ForwardKeysToOtherBots) { + if (BotConfig.DistributeKeys && !BotConfig.ForwardKeysToOtherBots) { do { if (iterator.MoveNext()) { currentBot = iterator.Current; @@ -830,12 +837,12 @@ namespace ArchiSteamFarm { } private bool LinkMobileAuthenticator() { - if (SteamGuardAccount != null) { + if (BotDatabase.SteamGuardAccount != null) { return false; } Logging.LogGenericInfo("Linking new ASF MobileAuthenticator...", BotName); - UserLogin userLogin = new UserLogin(SteamLogin, SteamPassword); + UserLogin userLogin = new UserLogin(BotConfig.SteamLogin, BotConfig.SteamPassword); LoginResult loginResult; while ((loginResult = userLogin.DoLogin()) != LoginResult.LoginOkay) { switch (loginResult) { @@ -862,14 +869,7 @@ namespace ArchiSteamFarm { } } - SteamGuardAccount = authenticatorLinker.LinkedAccount; - - try { - File.WriteAllText(MobileAuthenticatorFile, JsonConvert.SerializeObject(SteamGuardAccount)); - } catch (Exception e) { - Logging.LogGenericException(e, BotName); - return false; - } + BotDatabase.SteamGuardAccount = authenticatorLinker.LinkedAccount; AuthenticatorLinker.FinalizeResult finalizeResult = authenticatorLinker.FinalizeAddAuthenticator(Program.GetUserInput(BotName, Program.EUserInputType.SMS)); if (finalizeResult != AuthenticatorLinker.FinalizeResult.Success) { @@ -879,33 +879,30 @@ namespace ArchiSteamFarm { } Logging.LogGenericInfo("Successfully linked ASF as new mobile authenticator for this account!", BotName); - Program.GetUserInput(BotName, Program.EUserInputType.RevocationCode, SteamGuardAccount.RevocationCode); + Program.GetUserInput(BotName, Program.EUserInputType.RevocationCode, BotDatabase.SteamGuardAccount.RevocationCode); return true; } private bool DelinkMobileAuthenticator() { - if (SteamGuardAccount == null) { + if (BotDatabase.SteamGuardAccount == null) { return false; } - bool result = SteamGuardAccount.DeactivateAuthenticator(); - SteamGuardAccount = null; + bool result = BotDatabase.SteamGuardAccount.DeactivateAuthenticator(); - try { - File.Delete(MobileAuthenticatorFile); - } catch (Exception e) { - Logging.LogGenericException(e, BotName); + if (result) { + BotDatabase.SteamGuardAccount = null; } return result; } private void JoinMasterChat() { - if (SteamMasterClanID == 0) { + if (BotConfig.SteamMasterClanID == 0) { return; } - SteamFriends.JoinChat(SteamMasterClanID); + SteamFriends.JoinChat(BotConfig.SteamMasterClanID); } private void OnConnected(SteamClient.ConnectedCallback callback) { @@ -926,14 +923,6 @@ namespace ArchiSteamFarm { return; } - if (File.Exists(LoginKeyFile)) { - try { - LoginKey = File.ReadAllText(LoginKeyFile); - } catch (Exception e) { - Logging.LogGenericException(e, BotName); - } - } - byte[] sentryHash = null; if (File.Exists(SentryFile)) { try { @@ -944,20 +933,20 @@ namespace ArchiSteamFarm { } } - if (SteamLogin.Equals("null")) { - SteamLogin = Program.GetUserInput(BotName, Program.EUserInputType.Login); + if (string.IsNullOrEmpty(BotConfig.SteamLogin)) { + BotConfig.SteamLogin = Program.GetUserInput(BotName, Program.EUserInputType.Login); } - if (SteamPassword.Equals("null") && string.IsNullOrEmpty(LoginKey)) { - SteamPassword = Program.GetUserInput(BotName, Program.EUserInputType.Password); + if (string.IsNullOrEmpty(BotConfig.SteamPassword) && string.IsNullOrEmpty(BotDatabase.LoginKey)) { + BotConfig.SteamPassword = Program.GetUserInput(BotName, Program.EUserInputType.Password); } SteamUser.LogOn(new SteamUser.LogOnDetails { - Username = SteamLogin, - Password = SteamPassword, + Username = BotConfig.SteamLogin, + Password = BotConfig.SteamPassword, AuthCode = AuthCode, LoginID = LoginID, - LoginKey = LoginKey, + LoginKey = BotDatabase.LoginKey, TwoFactorCode = TwoFactorAuth, SentryFileHash = sentryHash, ShouldRememberPassword = true @@ -983,15 +972,8 @@ namespace ArchiSteamFarm { if (InvalidPassword) { InvalidPassword = false; - if (!string.IsNullOrEmpty(LoginKey)) { // InvalidPassword means usually that login key has expired, if we used it - LoginKey = null; - - try { - File.Delete(LoginKeyFile); - } catch (Exception e) { - Logging.LogGenericException(e, BotName); - } - + if (!string.IsNullOrEmpty(BotDatabase.LoginKey)) { // InvalidPassword means usually that login key has expired, if we used it + BotDatabase.LoginKey = null; Logging.LogGenericInfo("Removed expired login key", BotName); } else { // If we didn't use login key, InvalidPassword usually means we got captcha or other network-based throttling Logging.LogGenericInfo("Will retry after 25 minutes...", BotName); @@ -1024,7 +1006,7 @@ namespace ArchiSteamFarm { return; } - if (callback.PatronID != SteamMasterID) { + if (callback.PatronID != BotConfig.SteamMasterID) { return; } @@ -1040,7 +1022,7 @@ namespace ArchiSteamFarm { return; } - if (callback.ChatterID != SteamMasterID) { + if (callback.ChatterID != BotConfig.SteamMasterID) { return; } @@ -1069,7 +1051,7 @@ namespace ArchiSteamFarm { // TODO: Accept clan invites from master? break; default: - if (friend.SteamID == SteamMasterID) { + if (friend.SteamID == BotConfig.SteamMasterID) { SteamFriends.AddFriend(friend.SteamID); } break; @@ -1086,7 +1068,7 @@ namespace ArchiSteamFarm { return; } - if (callback.Sender != SteamMasterID) { + if (callback.Sender != BotConfig.SteamMasterID) { return; } @@ -1102,7 +1084,7 @@ namespace ArchiSteamFarm { return; } - if (callback.SteamID != SteamMasterID) { + if (callback.SteamID != BotConfig.SteamMasterID) { return; } @@ -1132,7 +1114,7 @@ namespace ArchiSteamFarm { return; } - if (!FarmOffline) { + if (!BotConfig.FarmOffline) { SteamFriends.SetPersonaState(EPersonaState.Online); } } @@ -1160,13 +1142,13 @@ namespace ArchiSteamFarm { switch (callback.Result) { case EResult.AccountLogonDenied: - AuthCode = Program.GetUserInput(SteamLogin, Program.EUserInputType.SteamGuard); + AuthCode = Program.GetUserInput(BotConfig.SteamLogin, Program.EUserInputType.SteamGuard); break; case EResult.AccountLoginDeniedNeedTwoFactor: - if (SteamGuardAccount == null) { - TwoFactorAuth = Program.GetUserInput(SteamLogin, Program.EUserInputType.TwoFactorAuthentication); + if (BotDatabase.SteamGuardAccount == null) { + TwoFactorAuth = Program.GetUserInput(BotConfig.SteamLogin, Program.EUserInputType.TwoFactorAuthentication); } else { - TwoFactorAuth = SteamGuardAccount.GenerateSteamGuardCode(); + TwoFactorAuth = BotDatabase.SteamGuardAccount.GenerateSteamGuardCode(); } break; case EResult.InvalidPassword: @@ -1176,7 +1158,7 @@ namespace ArchiSteamFarm { case EResult.OK: Logging.LogGenericInfo("Successfully logged on!", BotName); - if (UseAsfAsMobileAuthenticator && TwoFactorAuth == null && SteamGuardAccount == null) { + if (BotConfig.UseAsfAsMobileAuthenticator && TwoFactorAuth == null && BotDatabase.SteamGuardAccount == null) { LinkMobileAuthenticator(); } @@ -1184,27 +1166,23 @@ namespace ArchiSteamFarm { AuthCode = null; TwoFactorAuth = null; - if (!SteamNickname.Equals("null")) { - await SteamFriends.SetPersonaName(SteamNickname); - } - ResetGamesPlayed(); - if (SteamParentalPIN.Equals("null")) { - SteamParentalPIN = Program.GetUserInput(BotName, Program.EUserInputType.SteamParentalPIN); + if (string.IsNullOrEmpty(BotConfig.SteamParentalPIN)) { + BotConfig.SteamParentalPIN = Program.GetUserInput(BotName, Program.EUserInputType.SteamParentalPIN); } - if (!await ArchiWebHandler.Init(SteamClient, callback.WebAPIUserNonce, SteamParentalPIN).ConfigureAwait(false)) { + if (!await ArchiWebHandler.Init(SteamClient, callback.WebAPIUserNonce, BotConfig.SteamParentalPIN).ConfigureAwait(false)) { await Restart().ConfigureAwait(false); return; } - if (SteamMasterClanID != 0) { - await ArchiWebHandler.JoinClan(SteamMasterClanID).ConfigureAwait(false); + if (BotConfig.SteamMasterClanID != 0) { + await ArchiWebHandler.JoinClan(BotConfig.SteamMasterClanID).ConfigureAwait(false); JoinMasterChat(); } - if (Statistics) { + if (BotConfig.Statistics) { await ArchiWebHandler.JoinClan(ArchiSCFarmGroup).ConfigureAwait(false); SteamFriends.JoinChat(ArchiSCFarmGroup); } @@ -1231,12 +1209,7 @@ namespace ArchiSteamFarm { return; } - try { - File.WriteAllText(LoginKeyFile, callback.LoginKey); - } catch (Exception e) { - Logging.LogGenericException(e, BotName); - } - + BotDatabase.LoginKey = callback.LoginKey; SteamUser.AcceptNewLoginKey(callback); } @@ -1309,7 +1282,7 @@ namespace ArchiSteamFarm { return; } - if (!HandleOfflineMessages) { + if (!BotConfig.HandleOfflineMessages) { return; } @@ -1326,115 +1299,5 @@ namespace ArchiSteamFarm { await CardsFarmer.RestartFarming().ConfigureAwait(false); } } - - private bool ReadConfig() { - if (!File.Exists(ConfigFile)) { - return false; - } - - try { - using (XmlReader reader = XmlReader.Create(ConfigFile)) { - while (reader.Read()) { - if (reader.NodeType != XmlNodeType.Element) { - continue; - } - - string key = reader.Name; - if (string.IsNullOrEmpty(key)) { - continue; - } - - string value = reader.GetAttribute("value"); - if (string.IsNullOrEmpty(value)) { - continue; - } - - switch (key) { - case "Enabled": - Enabled = bool.Parse(value); - break; - case "SteamLogin": - SteamLogin = value; - break; - case "SteamPassword": - SteamPassword = value; - break; - case "SteamNickname": - SteamNickname = value; - break; - case "SteamApiKey": - SteamApiKey = value; - break; - case "SteamTradeToken": - SteamTradeToken = value; - break; - case "SteamParentalPIN": - SteamParentalPIN = value; - break; - case "SteamMasterID": - SteamMasterID = ulong.Parse(value); - break; - case "SteamMasterClanID": - SteamMasterClanID = ulong.Parse(value); - break; - case "StartOnLaunch": - StartOnLaunch = bool.Parse(value); - break; - case "UseAsfAsMobileAuthenticator": - UseAsfAsMobileAuthenticator = bool.Parse(value); - break; - case "CardDropsRestricted": - CardDropsRestricted = bool.Parse(value); - break; - case "FarmOffline": - FarmOffline = bool.Parse(value); - break; - case "HandleOfflineMessages": - HandleOfflineMessages = bool.Parse(value); - break; - case "ForwardKeysToOtherBots": - ForwardKeysToOtherBots = bool.Parse(value); - break; - case "DistributeKeys": - DistributeKeys = bool.Parse(value); - break; - case "ShutdownOnFarmingFinished": - ShutdownOnFarmingFinished = bool.Parse(value); - break; - case "SendOnFarmingFinished": - SendOnFarmingFinished = bool.Parse(value); - break; - case "SendTradePeriod": - SendTradePeriod = byte.Parse(value); - break; - case "Blacklist": - Blacklist.Clear(); - foreach (string appID in value.Split(',')) { - Blacklist.Add(uint.Parse(appID)); - } - break; - case "GamesPlayedWhileIdle": - GamesPlayedWhileIdle.Clear(); - foreach (string appID in value.Split(',')) { - GamesPlayedWhileIdle.Add(uint.Parse(appID)); - } - break; - case "Statistics": - Statistics = bool.Parse(value); - break; - default: - Logging.LogGenericWarning("Unrecognized config value: " + key + "=" + value, BotName); - break; - } - } - } - } catch (Exception e) { - Logging.LogGenericException(e, BotName); - Logging.LogGenericError("Your config for this bot instance is invalid, it won't run!", BotName); - return false; - } - - return true; - } } } diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs new file mode 100644 index 000000000..0f37439d6 --- /dev/null +++ b/ArchiSteamFarm/BotConfig.cs @@ -0,0 +1,252 @@ +/* + _ _ _ ____ _ _____ + / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___ + / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \ + / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | | +/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_| + + Copyright 2015-2016 Łukasz "JustArchi" Domeradzki + Contact: JustArchi@JustArchi.net + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; + +namespace ArchiSteamFarm { + internal sealed class BotConfig { + internal static readonly HashSet GlobalBlacklist = new HashSet { 303700, 335590, 368020, 425280 }; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool Enabled { get; private set; } = false; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool StartOnLaunch { get; private set; } = true; + + [JsonProperty] + internal string SteamLogin { get; set; } = null; + + [JsonProperty] + internal string SteamPassword { get; set; } = null; + + [JsonProperty] + internal string SteamParentalPIN { get; set; } = "0"; + + [JsonProperty] + internal string SteamApiKey { get; private set; } = null; + + [JsonProperty(Required = Required.DisallowNull)] + internal ulong SteamMasterID { get; private set; } = 0; + + [JsonProperty(Required = Required.DisallowNull)] + internal ulong SteamMasterClanID { get; private set; } = 0; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool CardDropsRestricted { get; private set; } = false; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool FarmOffline { get; private set; } = false; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool HandleOfflineMessages { get; private set; } = false; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool ForwardKeysToOtherBots { get; private set; } = false; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool DistributeKeys { get; private set; } = false; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool UseAsfAsMobileAuthenticator { get; private set; } = false; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool ShutdownOnFarmingFinished { get; private set; } = false; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool SendOnFarmingFinished { get; private set; } = false; + + [JsonProperty(Required = Required.DisallowNull)] + internal string SteamTradeToken { get; private set; } = null; + + [JsonProperty(Required = Required.DisallowNull)] + internal byte SendTradePeriod { get; private set; } = 0; + + [JsonProperty(Required = Required.DisallowNull)] + internal HashSet GamesPlayedWhileIdle { get; private set; } = new HashSet() { 0 }; + + [JsonProperty(Required = Required.DisallowNull)] + internal bool Statistics { get; private set; } = true; + + + internal static BotConfig Load(string path) { + if (!File.Exists(path)) { + return null; + } + + BotConfig botConfig; + try { + botConfig = JsonConvert.DeserializeObject(File.ReadAllText(path)); + } catch (Exception e) { + Logging.LogGenericException(e); + return null; + } + + return botConfig; + } + + // TODO: This should be removed soon + internal static BotConfig LoadOldFormat(string path) { + if (!File.Exists(path)) { + return null; + } + + BotConfig botConfig = new BotConfig(); + + try { + using (XmlReader reader = XmlReader.Create(path)) { + while (reader.Read()) { + if (reader.NodeType != XmlNodeType.Element) { + continue; + } + + string key = reader.Name; + if (string.IsNullOrEmpty(key)) { + continue; + } + + string value = reader.GetAttribute("value"); + if (string.IsNullOrEmpty(value)) { + continue; + } + + switch (key) { + case "Enabled": + botConfig.Enabled = bool.Parse(value); + break; + case "SteamLogin": + botConfig.SteamLogin = value; + break; + case "SteamPassword": + botConfig.SteamPassword = value; + break; + case "SteamApiKey": + botConfig.SteamApiKey = value; + break; + case "SteamTradeToken": + botConfig.SteamTradeToken = value; + break; + case "SteamParentalPIN": + botConfig.SteamParentalPIN = value; + break; + case "SteamMasterID": + botConfig.SteamMasterID = ulong.Parse(value); + break; + case "SteamMasterClanID": + botConfig.SteamMasterClanID = ulong.Parse(value); + break; + case "StartOnLaunch": + botConfig.StartOnLaunch = bool.Parse(value); + break; + case "UseAsfAsMobileAuthenticator": + botConfig.UseAsfAsMobileAuthenticator = bool.Parse(value); + break; + case "CardDropsRestricted": + botConfig.CardDropsRestricted = bool.Parse(value); + break; + case "FarmOffline": + botConfig.FarmOffline = bool.Parse(value); + break; + case "HandleOfflineMessages": + botConfig.HandleOfflineMessages = bool.Parse(value); + break; + case "ForwardKeysToOtherBots": + botConfig.ForwardKeysToOtherBots = bool.Parse(value); + break; + case "DistributeKeys": + botConfig.DistributeKeys = bool.Parse(value); + break; + case "ShutdownOnFarmingFinished": + botConfig.ShutdownOnFarmingFinished = bool.Parse(value); + break; + case "SendOnFarmingFinished": + botConfig.SendOnFarmingFinished = bool.Parse(value); + break; + case "SendTradePeriod": + botConfig.SendTradePeriod = byte.Parse(value); + break; + case "GamesPlayedWhileIdle": + botConfig.GamesPlayedWhileIdle.Clear(); + foreach (string appID in value.Split(',')) { + botConfig.GamesPlayedWhileIdle.Add(uint.Parse(appID)); + } + break; + case "Statistics": + botConfig.Statistics = bool.Parse(value); + break; + case "Blacklist": + case "SteamNickname": + break; + default: + Logging.LogGenericWarning("Unrecognized config value: " + key + "=" + value); + break; + } + } + } + } catch (Exception e) { + Logging.LogGenericException(e); + Logging.LogGenericError("Your config for this bot instance is invalid, it won't run!"); + return null; + } + + // Fixups for new format + if (botConfig.SteamLogin != null && botConfig.SteamLogin.Equals("null")) { + botConfig.SteamLogin = null; + } + + if (botConfig.SteamPassword != null && botConfig.SteamPassword.Equals("null")) { + botConfig.SteamPassword = null; + } + + if (botConfig.SteamApiKey != null && botConfig.SteamApiKey.Equals("null")) { + botConfig.SteamApiKey = null; + } + + if (botConfig.SteamParentalPIN != null && botConfig.SteamParentalPIN.Equals("null")) { + botConfig.SteamParentalPIN = null; + } + + return botConfig; + } + + // This constructor is used only by deserializer + private BotConfig() { } + + // TODO: This should be removed soon + internal bool Convert(string path) { + try { + File.WriteAllText(path, JsonConvert.SerializeObject(this, Newtonsoft.Json.Formatting.Indented)); + } catch (Exception e) { + Logging.LogGenericException(e); + return false; + } + + Logging.LogGenericWarning("Your config was converted to new ASF V2.0 format"); + return true; + } + } +} diff --git a/ArchiSteamFarm/BotDatabase.cs b/ArchiSteamFarm/BotDatabase.cs new file mode 100644 index 000000000..29cbe80d4 --- /dev/null +++ b/ArchiSteamFarm/BotDatabase.cs @@ -0,0 +1,96 @@ +/* + _ _ _ ____ _ _____ + / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___ + / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \ + / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | | +/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_| + + Copyright 2015-2016 Łukasz "JustArchi" Domeradzki + Contact: JustArchi@JustArchi.net + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +using Newtonsoft.Json; +using SteamAuth; +using System; +using System.IO; + +namespace ArchiSteamFarm { + internal sealed class BotDatabase { + internal string LoginKey { + get { + return _LoginKey; + } + set { + _LoginKey = value; + Save(); + } + } + + internal SteamGuardAccount SteamGuardAccount { + get { + return _SteamGuardAccount; + } + set { + _SteamGuardAccount = value; + Save(); + } + } + + [JsonProperty(Required = Required.AllowNull)] + private string _LoginKey; + + [JsonProperty(Required = Required.AllowNull)] + private SteamGuardAccount _SteamGuardAccount; + + private string FilePath; + + internal static BotDatabase Load(string filePath) { + if (!File.Exists(filePath)) { + return new BotDatabase(filePath); + } + + BotDatabase botDatabase; + try { + botDatabase = JsonConvert.DeserializeObject(File.ReadAllText(filePath)); + } catch (Exception e) { + Logging.LogGenericException(e); + return null; + } + + botDatabase.FilePath = filePath; + return botDatabase; + } + + // This constructor is used when creating new database + private BotDatabase(string filePath) { + FilePath = filePath; + Save(); + } + + // This constructor is used only by deserializer + private BotDatabase() { } + + private void Save() { + lock (FilePath) { + try { + File.WriteAllText(FilePath, JsonConvert.SerializeObject(this)); + } catch (Exception e) { + Logging.LogGenericException(e); + } + } + } + } +} diff --git a/ArchiSteamFarm/CardsFarmer.cs b/ArchiSteamFarm/CardsFarmer.cs index 042bc7b93..4fd972c03 100755 --- a/ArchiSteamFarm/CardsFarmer.cs +++ b/ArchiSteamFarm/CardsFarmer.cs @@ -178,7 +178,7 @@ namespace ArchiSteamFarm { bool farmedSomething = false; // Now the algorithm used for farming depends on whether account is restricted or not - if (Bot.CardDropsRestricted) { // If we have restricted card drops, we use complex algorithm + if (Bot.BotConfig.CardDropsRestricted) { // If we have restricted card drops, we use complex algorithm Logging.LogGenericInfo("Chosen farming algorithm: Complex", Bot.BotName); while (GamesToFarm.Count > 0) { List gamesToFarmSolo = GetGamesToFarmSolo(GamesToFarm); @@ -294,7 +294,7 @@ namespace ArchiSteamFarm { } // If we have restricted card drops, actually do check hours of all games that are left to farm - if (Bot.CardDropsRestricted) { + if (Bot.BotConfig.CardDropsRestricted) { tasks = new List(GamesToFarm.Keys.Count); Logging.LogGenericInfo("Checking hours...", Bot.BotName); foreach (uint appID in GamesToFarm.Keys) { @@ -327,7 +327,7 @@ namespace ArchiSteamFarm { continue; } - if (Bot.GlobalBlacklist.Contains(appID) || Bot.Blacklist.Contains(appID)) { + if (BotConfig.GlobalBlacklist.Contains(appID)) { continue; } diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 80781a6c3..93a156116 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -267,14 +267,25 @@ namespace ArchiSteamFarm { // Before attempting to connect, initialize our list of CMs Bot.RefreshCMs().Wait(); - foreach (var configFile in Directory.EnumerateFiles(ConfigDirectory, "*.xml")) { + foreach (var configFile in Directory.EnumerateFiles(ConfigDirectory, "*.json")) { string botName = Path.GetFileNameWithoutExtension(configFile); Bot bot = new Bot(botName); - if (!bot.Enabled) { + if (!bot.BotConfig.Enabled) { Logging.LogGenericInfo("Not starting this instance because it's disabled in config file", botName); } } + // CONVERSION START + foreach (var configFile in Directory.EnumerateFiles(ConfigDirectory, "*.xml")) { + string botName = Path.GetFileNameWithoutExtension(configFile); + Logging.LogGenericWarning("Found legacy " + botName + ".xml config file, it will now be converted to new ASF V2.0 format!"); + Bot bot = new Bot(botName); + if (!bot.BotConfig.Enabled) { + Logging.LogGenericInfo("Not starting this instance because it's disabled in config file", botName); + } + } + // CONVERSION END + // Check if we got any bots running OnBotShutdown(); diff --git a/ArchiSteamFarm/Properties/AssemblyInfo.cs b/ArchiSteamFarm/Properties/AssemblyInfo.cs index c3172fe94..fc1f591cf 100644 --- a/ArchiSteamFarm/Properties/AssemblyInfo.cs +++ b/ArchiSteamFarm/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // 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.7.0.0")] -[assembly: AssemblyFileVersion("1.7.0.0")] +[assembly: AssemblyVersion("2.0.0.0")] +[assembly: AssemblyFileVersion("2.0.0.0")] diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index a1b71dd89..84250d419 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -88,7 +88,7 @@ namespace ArchiSteamFarm { return; } - if (tradeOffer.items_to_give.Count == 0 || tradeOffer.OtherSteamID64 == Bot.SteamMasterID) { + if (tradeOffer.items_to_give.Count == 0 || tradeOffer.OtherSteamID64 == Bot.BotConfig.SteamMasterID) { Logging.LogGenericInfo("Accepting trade: " + tradeID, Bot.BotName); await Bot.ArchiWebHandler.AcceptTradeOffer(tradeID).ConfigureAwait(false); } else { diff --git a/ArchiSteamFarm/config/example.json b/ArchiSteamFarm/config/example.json new file mode 100644 index 000000000..dd8ff62fa --- /dev/null +++ b/ArchiSteamFarm/config/example.json @@ -0,0 +1,24 @@ +{ + "Enabled": false, + "StartOnLaunch": true, + "SteamLogin": null, + "SteamPassword": null, + "SteamParentalPIN": "0", + "SteamApiKey": null, + "SteamMasterID": 0, + "SteamMasterClanID": 0, + "CardDropsRestricted": false, + "FarmOffline": false, + "HandleOfflineMessages": false, + "ForwardKeysToOtherBots": false, + "DistributeKeys": false, + "UseAsfAsMobileAuthenticator": false, + "ShutdownOnFarmingFinished": false, + "SendOnFarmingFinished": false, + "SteamTradeToken": "null", + "SendTradePeriod": 0, + "GamesPlayedWhileIdle": [ + 0 + ], + "Statistics": true +} \ No newline at end of file diff --git a/ArchiSteamFarm/config/example.xml b/ArchiSteamFarm/config/example.xml deleted file mode 100755 index e7063911b..000000000 --- a/ArchiSteamFarm/config/example.xml +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ArchiSteamFarm/config/minimal.json b/ArchiSteamFarm/config/minimal.json new file mode 100644 index 000000000..559e54280 --- /dev/null +++ b/ArchiSteamFarm/config/minimal.json @@ -0,0 +1,24 @@ +{ + "Enabled": false, + "StartOnLaunch": true, + "SteamLogin": null, + "SteamPassword": null, + "SteamParentalPIN": "0", + "SteamApiKey": null, + "SteamMasterID": 0, + "SteamMasterClanID": 0, + "CardDropsRestricted": false, + "FarmOffline": false, + "HandleOfflineMessages": false, + "ForwardKeysToOtherBots": false, + "DistributeKeys": false, + "UseAsfAsMobileAuthenticator": false, + "ShutdownOnFarmingFinished": false, + "SendOnFarmingFinished": false, + "SteamTradeToken": null, + "SendTradePeriod": 0, + "GamesPlayedWhileIdle": [ + 0 + ], + "Statistics": true +} \ No newline at end of file diff --git a/ArchiSteamFarm/config/minimal.xml b/ArchiSteamFarm/config/minimal.xml deleted file mode 100644 index b00aa7997..000000000 --- a/ArchiSteamFarm/config/minimal.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - -