From 9403985b14d269f6c31140d3cf86e7b9392cbcfd Mon Sep 17 00:00:00 2001 From: JustArchi Date: Mon, 30 May 2016 00:09:42 +0200 Subject: [PATCH] LoggedInElsewhere improvements Previously we had rather half-blind mechanism of trying to play given games, expecting a disconnect, and reconnecting in AccountPlayingDelay minutes. Now instead we have proper event-based handling - ASF listens on each PlayingSessionState event and updates availability of farming accordingly, not only resuming farming immediately after it's possible, but also limiting number of reconnects and other issues which could be caused by previous approach. I bet this can be even further improved to not receive LoggedInElsewhere and disconnect error when user starts playing a game, but that's misc compared to gigantic improvement in this commit --- ArchiSteamFarm/ArchiHandler.cs | 25 ++++++++++++++++++ ArchiSteamFarm/Bot.cs | 45 +++++++++++++++++++-------------- ArchiSteamFarm/CardsFarmer.cs | 12 +++++++-- ArchiSteamFarm/GlobalConfig.cs | 3 --- ArchiSteamFarm/config/ASF.json | 1 - ConfigGenerator/GlobalConfig.cs | 3 --- 6 files changed, 61 insertions(+), 28 deletions(-) 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;