diff --git a/ArchiSteamFarm/ArchiHandler.cs b/ArchiSteamFarm/ArchiHandler.cs index 3c538dd1f..65b9db445 100644 --- a/ArchiSteamFarm/ArchiHandler.cs +++ b/ArchiSteamFarm/ArchiHandler.cs @@ -105,6 +105,19 @@ namespace ArchiSteamFarm { } } + internal sealed class PlayingSessionStateCallback : CallbackMsg { + internal readonly bool PlayingBlocked; + + internal PlayingSessionStateCallback(JobID jobID, CMsgClientPlayingSessionState msg) { + if ((jobID == null) || (msg == null)) { + throw new ArgumentNullException(nameof(jobID) + " || " + nameof(msg)); + } + + JobID = jobID; + PlayingBlocked = msg.playing_blocked; + } + } + internal sealed class PurchaseResponseCallback : CallbackMsg { internal enum EPurchaseResult : sbyte { [SuppressMessage("ReSharper", "UnusedMember.Global")] @@ -278,6 +291,9 @@ namespace ArchiSteamFarm { case EMsg.ClientItemAnnouncements: HandleItemAnnouncements(packetMsg); break; + case EMsg.ClientPlayingSessionState: + HandlePlayingSessionState(packetMsg); + break; case EMsg.ClientPurchaseResponse: HandlePurchaseResponse(packetMsg); break; @@ -305,6 +321,15 @@ namespace ArchiSteamFarm { Client.PostCallback(new NotificationsCallback(packetMsg.TargetJobID, response.Body)); } + private void HandlePlayingSessionState(IPacketMsg packetMsg) { + if (packetMsg == null) { + return; + } + + ClientMsgProtobuf response = new ClientMsgProtobuf(packetMsg); + Client.PostCallback(new PlayingSessionStateCallback(packetMsg.TargetJobID, response.Body)); + } + private void HandlePurchaseResponse(IPacketMsg packetMsg) { if (packetMsg == null) { return; diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index 0768666d0..ce9cae48f 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -67,8 +67,9 @@ namespace ArchiSteamFarm { private readonly Trading Trading; internal bool KeepRunning { get; private set; } + internal bool PlayingBlocked { get; private set; } - private bool InvalidPassword, LoggedInElsewhere, FirstTradeSent, SkipFirstShutdown; + private bool FirstTradeSent, InvalidPassword, SkipFirstShutdown; private string AuthCode, TwoFactorCode; internal static async Task RefreshCMs(uint cellID) { @@ -192,6 +193,7 @@ namespace ArchiSteamFarm { CallbackManager.Subscribe(OnNotifications); CallbackManager.Subscribe(OnOfflineMessage); + CallbackManager.Subscribe(OnPlayingSessionState); CallbackManager.Subscribe(OnPurchaseResponse); ArchiWebHandler = new ArchiWebHandler(this); @@ -1475,16 +1477,6 @@ namespace ArchiSteamFarm { Logging.LogGenericInfo("Will retry after 25 minutes...", BotName); await Utilities.SleepAsync(25 * 60 * 1000).ConfigureAwait(false); // Captcha disappears after around 20 minutes, so we make it 25 } - } else if (LoggedInElsewhere) { - LoggedInElsewhere = false; - - if (Program.GlobalConfig.AccountPlayingDelay == 0) { - Stop(); - return; - } - - Logging.LogGenericInfo("Account is being used elsewhere, ASF will try to resume farming in " + Program.GlobalConfig.AccountPlayingDelay + " minutes...", BotName); - await Utilities.SleepAsync(Program.GlobalConfig.AccountPlayingDelay * 60 * 1000).ConfigureAwait(false); } if (!KeepRunning || SteamClient.IsConnected) { @@ -1619,14 +1611,6 @@ namespace ArchiSteamFarm { } Logging.LogGenericInfo("Logged off of Steam: " + callback.Result, BotName); - - switch (callback.Result) { - case EResult.AlreadyLoggedInElsewhere: - case EResult.LoggedInElsewhere: - case EResult.LogonSessionReplaced: - LoggedInElsewhere = true; - break; - } } private async void OnLoggedOn(SteamUser.LoggedOnCallback callback) { @@ -1660,6 +1644,8 @@ namespace ArchiSteamFarm { case EResult.OK: Logging.LogGenericInfo("Successfully logged on!", BotName); + PlayingBlocked = false; // If playing is really blocked, we'll be notified in a callback, old status doesn't matter + if (callback.CellID != 0) { Program.GlobalDatabase.CellID = callback.CellID; } @@ -1711,6 +1697,7 @@ namespace ArchiSteamFarm { Task.Run(() => Trading.CheckTrades()).Forget(); + await Utilities.SleepAsync(1000).ConfigureAwait(false); // Wait a second for eventual PlayingSessionStateCallback CardsFarmer.StartFarming().Forget(); break; case EResult.NoConnection: @@ -1810,6 +1797,26 @@ namespace ArchiSteamFarm { SteamFriends.RequestOfflineMessages(); } + private void OnPlayingSessionState(ArchiHandler.PlayingSessionStateCallback callback) { + if (callback == null) { + Logging.LogNullError(nameof(callback)); + return; + } + + if (callback.PlayingBlocked == PlayingBlocked) { + return; // No status update, we're not interested + } + + if (callback.PlayingBlocked) { + PlayingBlocked = true; + Logging.LogGenericInfo("Account is currently being used, ASF will resume farming when it's free...", BotName); + } else { + PlayingBlocked = false; + Logging.LogGenericInfo("Account is no longer occupied, farming process resumed!", BotName); + CardsFarmer.StartFarming().Forget(); + } + } + private void OnPurchaseResponse(ArchiHandler.PurchaseResponseCallback callback) { if (callback == null) { return; diff --git a/ArchiSteamFarm/CardsFarmer.cs b/ArchiSteamFarm/CardsFarmer.cs index 226d82175..2b9310e63 100755 --- a/ArchiSteamFarm/CardsFarmer.cs +++ b/ArchiSteamFarm/CardsFarmer.cs @@ -80,13 +80,13 @@ namespace ArchiSteamFarm { } internal async Task StartFarming() { - if (NowFarming || ManualMode) { + if (NowFarming || ManualMode || Bot.PlayingBlocked) { return; } await FarmingSemaphore.WaitAsync().ConfigureAwait(false); - if (NowFarming || ManualMode) { + if (NowFarming || ManualMode || Bot.PlayingBlocked) { FarmingSemaphore.Release(); // We have nothing to do, don't forget to release semaphore return; } @@ -99,6 +99,14 @@ namespace ArchiSteamFarm { } Logging.LogGenericInfo("We have a total of " + GamesToFarm.Count + " games to farm on this account...", Bot.BotName); + + // This is the last moment for final check if we can farm + if (Bot.PlayingBlocked) { + Logging.LogGenericInfo("But account is currently occupied, so farming is stopped!"); + FarmingSemaphore.Release(); // We have nothing to do, don't forget to release semaphore + return; + } + NowFarming = true; FarmingSemaphore.Release(); // From this point we allow other calls to shut us down diff --git a/ArchiSteamFarm/GlobalConfig.cs b/ArchiSteamFarm/GlobalConfig.cs index 20135ecb0..17ee7fdb3 100644 --- a/ArchiSteamFarm/GlobalConfig.cs +++ b/ArchiSteamFarm/GlobalConfig.cs @@ -79,9 +79,6 @@ namespace ArchiSteamFarm { [JsonProperty(Required = Required.DisallowNull)] internal byte FarmingDelay { get; private set; } = DefaultFarmingDelay; - [JsonProperty(Required = Required.DisallowNull)] - internal byte AccountPlayingDelay { get; private set; } = 5; - [JsonProperty(Required = Required.DisallowNull)] internal byte LoginLimiterDelay { get; private set; } = 7; diff --git a/ArchiSteamFarm/config/ASF.json b/ArchiSteamFarm/config/ASF.json index a8f3bf25a..eec0fae72 100644 --- a/ArchiSteamFarm/config/ASF.json +++ b/ArchiSteamFarm/config/ASF.json @@ -9,7 +9,6 @@ "MaxFarmingTime": 10, "IdleFarmingPeriod": 3, "FarmingDelay": 5, - "AccountPlayingDelay": 5, "LoginLimiterDelay": 7, "InventoryLimiterDelay": 3, "ForceHttp": false, diff --git a/ConfigGenerator/GlobalConfig.cs b/ConfigGenerator/GlobalConfig.cs index 582684ba5..ef40c37e6 100644 --- a/ConfigGenerator/GlobalConfig.cs +++ b/ConfigGenerator/GlobalConfig.cs @@ -78,9 +78,6 @@ namespace ConfigGenerator { [JsonProperty(Required = Required.DisallowNull)] public byte FarmingDelay { get; set; } = DefaultFarmingDelay; - [JsonProperty(Required = Required.DisallowNull)] - public byte AccountPlayingDelay { get; set; } = 5; - [JsonProperty(Required = Required.DisallowNull)] public byte LoginLimiterDelay { get; set; } = 7;