diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index c26ea87e8..60916e545 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -337,35 +337,85 @@ namespace ArchiSteamFarm { } } - internal async Task IsReleased(uint appID) { + internal async Task GetAppIDForIdling(uint appID, bool allowRecursiveSeriesDiscovery = true) { if (appID == 0) { ArchiLogger.LogNullError(nameof(appID)); - return null; + return 0; } - AsyncJobMultiple.ResultSet productInfo; + AsyncJobMultiple.ResultSet productInfoResultSet; try { - productInfo = await SteamApps.PICSGetProductInfo(appID, null); + productInfoResultSet = await SteamApps.PICSGetProductInfo(appID, null, false); } catch (Exception e) { ArchiLogger.LogGenericException(e); - return null; + return appID; } - foreach (string releaseState in productInfo.Results.SelectMany(productResult => productResult.Apps).Where(app => appID == app.Key).Select(app => app.Value.KeyValues["common"]["ReleaseState"].Value).Where(releaseState => !string.IsNullOrEmpty(releaseState))) { - switch (releaseState) { - case "released": - return true; - case "preloadonly": - case "prerelease": - return false; - default: - ArchiLogger.LogGenericWarning(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(releaseState), releaseState)); - return null; + foreach (Dictionary productInfoApps in productInfoResultSet.Results.Select(result => result.Apps)) { + SteamApps.PICSProductInfoCallback.PICSProductInfo productInfoApp; + if (!productInfoApps.TryGetValue(appID, out productInfoApp)) { + continue; } + + KeyValue productInfo = productInfoApp.KeyValues; + if (productInfo == KeyValue.Invalid) { + ArchiLogger.LogNullError(nameof(productInfo)); + break; + } + + KeyValue commonProductInfo = productInfo["common"]; + if (commonProductInfo == KeyValue.Invalid) { + ArchiLogger.LogNullError(nameof(commonProductInfo)); + break; + } + + string releaseState = commonProductInfo["ReleaseState"].Value; + if (!string.IsNullOrEmpty(releaseState)) { + switch (releaseState) { + case "released": + break; + case "preloadonly": + case "prerelease": + return 0; + default: + ArchiLogger.LogGenericWarning(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(releaseState), releaseState)); + break; + } + } + + string type = commonProductInfo["type"].Value; + if (string.IsNullOrEmpty(type) || !type.Equals("Series")) { + return appID; + } + + if (!allowRecursiveSeriesDiscovery) { + return 0; + } + + string listOfDlc = productInfo["extended"]["listofdlc"].Value; + if (string.IsNullOrEmpty(listOfDlc)) { + return appID; + } + + string[] dlcAppIDsString = listOfDlc.Split(','); + foreach (string dlcAppIDString in dlcAppIDsString) { + uint dlcAppID; + if (!uint.TryParse(dlcAppIDString, out dlcAppID)) { + ArchiLogger.LogNullError(nameof(dlcAppID)); + break; + } + + dlcAppID = await GetAppIDForIdling(dlcAppID, false).ConfigureAwait(false); + if (dlcAppID != 0) { + return dlcAppID; + } + } + + return 0; } - return null; + return appID; } internal async Task LootIfNeeded() { diff --git a/ArchiSteamFarm/CardsFarmer.cs b/ArchiSteamFarm/CardsFarmer.cs index 6e170b613..1e4349695 100755 --- a/ArchiSteamFarm/CardsFarmer.cs +++ b/ArchiSteamFarm/CardsFarmer.cs @@ -525,10 +525,14 @@ namespace ArchiSteamFarm { } bool success = true; - bool? isReleased = await Bot.IsReleased(game.AppID).ConfigureAwait(false); - if (isReleased.GetValueOrDefault(true)) { - Bot.ArchiHandler.PlayGame(game.AppID, Bot.BotConfig.CustomGamePlayedWhileFarming); + uint appID = await Bot.GetAppIDForIdling(game.AppID).ConfigureAwait(false); + if (appID != 0) { + if (appID != game.AppID) { + Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningIdlingGameMismatch, game.AppID, game.GameName, appID)); + } + + Bot.ArchiHandler.PlayGame(appID, Bot.BotConfig.CustomGamePlayedWhileFarming); DateTime endFarmingDate = DateTime.UtcNow.AddHours(Program.GlobalConfig.MaxFarmingTime); bool? keepFarming = await ShouldFarm(game).ConfigureAwait(false); @@ -552,7 +556,7 @@ namespace ArchiSteamFarm { } } else { IgnoredAppIDs[game.AppID] = DateTime.UtcNow; - Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingGameNotReleasedYet, game.AppID, game.GameName)); + Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingGameNotPossible, game.AppID, game.GameName)); } Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StoppedIdling, game.AppID, game.GameName)); diff --git a/ArchiSteamFarm/Localization/Strings.Designer.cs b/ArchiSteamFarm/Localization/Strings.Designer.cs index 632cc5670..dd4a4a249 100644 --- a/ArchiSteamFarm/Localization/Strings.Designer.cs +++ b/ArchiSteamFarm/Localization/Strings.Designer.cs @@ -955,11 +955,11 @@ namespace ArchiSteamFarm.Localization { } /// - /// Looks up a localized string similar to Idling {0} ({1}) is temporarily disabled, as that game was not released yet.. + /// Looks up a localized string similar to Idling {0} ({1}) is temporarily disabled, as ASF is not able to play that game at the moment.. /// - internal static string IdlingGameNotReleasedYet { + internal static string IdlingGameNotPossible { get { - return ResourceManager.GetString("IdlingGameNotReleasedYet", resourceCulture); + return ResourceManager.GetString("IdlingGameNotPossible", resourceCulture); } } @@ -1431,6 +1431,15 @@ namespace ArchiSteamFarm.Localization { } } + /// + /// Looks up a localized string similar to ASF detected appID mismatch for {0} ({1}) and will use appID of {2} instead.. + /// + internal static string WarningIdlingGameMismatch { + get { + return ResourceManager.GetString("WarningIdlingGameMismatch", resourceCulture); + } + } + /// /// Looks up a localized string similar to Please review our privacy policy section on the wiki if you're concerned about what ASF is in fact doing!. /// diff --git a/ArchiSteamFarm/Localization/Strings.resx b/ArchiSteamFarm/Localization/Strings.resx index e3de37a1d..c546a6970 100644 --- a/ArchiSteamFarm/Localization/Strings.resx +++ b/ArchiSteamFarm/Localization/Strings.resx @@ -697,8 +697,12 @@ StackTrace: ASF will attempt to use your preferred {0} culture, but translation in that language was completed only in {1}. Perhaps you could help us improve ASF translation for your language? {0} will be replaced by culture code, such as "en-US", {1} will be replaced by completeness percentage, such as "78.5%" - - Idling {0} ({1}) is temporarily disabled, as that game was not released yet. + + Idling {0} ({1}) is temporarily disabled, as ASF is not able to play that game at the moment. {0} will be replaced by game's appID (number), {1} will be replaced by game's name + + ASF detected appID mismatch for {0} ({1}) and will use appID of {2} instead. + {0} will be replaced by game's appID (number), {1} will be replaced by game's name, {2} will be replaced by game's appID (number) + \ No newline at end of file