Correct usage of IdleRefundableGames

This commit is contained in:
JustArchi
2019-08-10 01:24:22 +02:00
parent 51ccd950ef
commit 7d197ecebf
2 changed files with 48 additions and 23 deletions

View File

@@ -546,17 +546,17 @@ namespace ArchiSteamFarm {
return Environment.NewLine + "<" + botName + "> " + response;
}
internal async Task<(uint PlayableAppID, DateTime IgnoredUntil)> GetAppDataForIdling(uint appID, float hoursPlayed, bool allowRecursiveDiscovery = true, bool optimisticDiscovery = true) {
internal async Task<(uint PlayableAppID, DateTime IgnoredUntil, bool IgnoredGlobally)> GetAppDataForIdling(uint appID, float hoursPlayed, bool allowRecursiveDiscovery = true, bool optimisticDiscovery = true) {
if ((appID == 0) || (hoursPlayed < 0)) {
ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(hoursPlayed));
return (0, DateTime.MaxValue);
return (0, DateTime.MaxValue, true);
}
HashSet<uint> packageIDs = ASF.GlobalDatabase.GetPackageIDs(appID, OwnedPackageIDs.Keys);
if ((packageIDs == null) || (packageIDs.Count == 0)) {
return (0, DateTime.MaxValue);
return (0, DateTime.MaxValue, true);
}
if ((hoursPlayed < CardsFarmer.HoursForRefund) && !BotConfig.IdleRefundableGames) {
@@ -576,7 +576,7 @@ namespace ArchiSteamFarm {
DateTime playableIn = mostRecent.AddDays(CardsFarmer.DaysForRefund);
if (playableIn > DateTime.UtcNow) {
return (0, playableIn);
return (0, playableIn, false);
}
}
}
@@ -596,7 +596,7 @@ namespace ArchiSteamFarm {
}
if (productInfoResultSet == null) {
return (optimisticDiscovery ? appID : 0, DateTime.MinValue);
return (optimisticDiscovery ? appID : 0, DateTime.MinValue, true);
}
foreach (Dictionary<uint, SteamApps.PICSProductInfoCallback.PICSProductInfo> productInfoApps in productInfoResultSet.Results.Select(result => result.Apps)) {
@@ -627,7 +627,7 @@ namespace ArchiSteamFarm {
break;
case "PRELOADONLY":
case "PRERELEASE":
return (0, DateTime.MaxValue);
return (0, DateTime.MaxValue, true);
default:
ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(releaseState), releaseState));
@@ -638,7 +638,7 @@ namespace ArchiSteamFarm {
string type = commonProductInfo["type"].Value;
if (string.IsNullOrEmpty(type)) {
return (appID, DateTime.MinValue);
return (appID, DateTime.MinValue, true);
}
// We must convert this to uppercase, since Valve doesn't stick to any convention and we can have a case mismatch
@@ -652,7 +652,7 @@ namespace ArchiSteamFarm {
case "TOOL":
case "VIDEO":
// Types that can be idled
return (appID, DateTime.MinValue);
return (appID, DateTime.MinValue, true);
case "ADVERTISING":
case "DEMO":
case "DLC":
@@ -667,13 +667,13 @@ namespace ArchiSteamFarm {
}
if (!allowRecursiveDiscovery) {
return (0, DateTime.MinValue);
return (0, DateTime.MinValue, true);
}
string listOfDlc = productInfo["extended"]["listofdlc"].Value;
if (string.IsNullOrEmpty(listOfDlc)) {
return (appID, DateTime.MinValue);
return (appID, DateTime.MinValue, true);
}
string[] dlcAppIDsTexts = listOfDlc.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
@@ -685,17 +685,17 @@ namespace ArchiSteamFarm {
break;
}
(uint playableAppID, _) = await GetAppDataForIdling(dlcAppID, hoursPlayed, false, false).ConfigureAwait(false);
(uint playableAppID, _, _) = await GetAppDataForIdling(dlcAppID, hoursPlayed, false, false).ConfigureAwait(false);
if (playableAppID != 0) {
return (playableAppID, DateTime.MinValue);
return (playableAppID, DateTime.MinValue, true);
}
}
return (appID, DateTime.MinValue);
return (appID, DateTime.MinValue, true);
}
return ((productInfoResultSet.Complete && !productInfoResultSet.Failed) || optimisticDiscovery ? appID : 0, DateTime.MinValue);
return ((productInfoResultSet.Complete && !productInfoResultSet.Failed) || optimisticDiscovery ? appID : 0, DateTime.MinValue, true);
}
internal static string GetFilePath(string botName, EFileType fileType) {

View File

@@ -47,7 +47,7 @@ namespace ArchiSteamFarm {
[PublicAPI]
public static readonly ImmutableHashSet<uint> SalesBlacklist = ImmutableHashSet.Create<uint>(267420, 303700, 335590, 368020, 425280, 480730, 566020, 639900, 762800, 876740, 991980);
private static readonly ConcurrentDictionary<uint, DateTime> IgnoredAppIDs = new ConcurrentDictionary<uint, DateTime>(); // Reserved for unreleased games
private static readonly ConcurrentDictionary<uint, DateTime> GloballyIgnoredAppIDs = new ConcurrentDictionary<uint, DateTime>(); // Reserved for unreleased games
// Games that were confirmed to show false status on general badges page
private static readonly ImmutableHashSet<uint> UntrustedAppIDs = ImmutableHashSet.Create<uint>(440, 570, 730);
@@ -71,6 +71,14 @@ namespace ArchiSteamFarm {
private readonly SemaphoreSlim FarmingInitializationSemaphore = new SemaphoreSlim(1, 1);
private readonly SemaphoreSlim FarmingResetSemaphore = new SemaphoreSlim(0, 1);
private readonly Timer IdleFarmingTimer;
private readonly ConcurrentDictionary<uint, DateTime> LocallyIgnoredAppIDs = new ConcurrentDictionary<uint, DateTime>();
private IEnumerable<ConcurrentDictionary<uint, DateTime>> SourcesOfIgnoredAppIDs {
get {
yield return GloballyIgnoredAppIDs;
yield return LocallyIgnoredAppIDs;
}
}
internal bool NowFarming { get; private set; }
@@ -114,6 +122,9 @@ namespace ArchiSteamFarm {
}
internal async Task OnNewGameAdded() {
// This update has a potential to modify local ignores, therefore we need to purge our cache
LocallyIgnoredAppIDs.Clear();
ShouldResumeFarming = true;
// We aim to have a maximum of 2 tasks, one already parsing, and one waiting in the queue
@@ -404,14 +415,26 @@ namespace ArchiSteamFarm {
continue;
}
if (IgnoredAppIDs.TryGetValue(appID, out DateTime ignoredUntil)) {
if (ignoredUntil < DateTime.UtcNow) {
// This game served its time as being ignored
IgnoredAppIDs.TryRemove(appID, out _);
} else {
// This game is still ignored
bool ignored = false;
foreach (ConcurrentDictionary<uint, DateTime> sourceOfIgnoredAppIDs in SourcesOfIgnoredAppIDs) {
if (!sourceOfIgnoredAppIDs.TryGetValue(appID, out DateTime ignoredUntil)) {
continue;
}
if (ignoredUntil > DateTime.UtcNow) {
// This game is still ignored
ignored = true;
break;
}
// This game served its time as being ignored
sourceOfIgnoredAppIDs.TryRemove(appID, out _);
}
if (ignored) {
continue;
}
// Cards
@@ -1019,10 +1042,12 @@ namespace ArchiSteamFarm {
return false;
}
(uint playableAppID, DateTime ignoredUntil) = await Bot.GetAppDataForIdling(game.AppID, game.HoursPlayed).ConfigureAwait(false);
(uint playableAppID, DateTime ignoredUntil, bool ignoredGlobally) = await Bot.GetAppDataForIdling(game.AppID, game.HoursPlayed).ConfigureAwait(false);
if (playableAppID == 0) {
IgnoredAppIDs[game.AppID] = ignoredUntil < DateTime.MaxValue ? ignoredUntil : DateTime.UtcNow.AddHours(HoursToIgnore);
ConcurrentDictionary<uint, DateTime> ignoredAppIDs = ignoredGlobally ? GloballyIgnoredAppIDs : LocallyIgnoredAppIDs;
ignoredAppIDs[game.AppID] = (ignoredUntil > DateTime.MinValue) && (ignoredUntil < DateTime.MaxValue) ? ignoredUntil : DateTime.UtcNow.AddHours(HoursToIgnore);
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingGameNotPossible, game.AppID, game.GameName));
return false;