Add farming time approximation

Because @MaduRUDE asked nicely
This commit is contained in:
JustArchi 2016-12-26 22:07:49 +01:00
parent 9b56734bad
commit 33edc81116
13 changed files with 5571 additions and 16 deletions

View file

@ -35,6 +35,8 @@ using SteamKit2.Internal;
namespace ArchiSteamFarm { namespace ArchiSteamFarm {
internal sealed class ArchiHandler : ClientMsgHandler { internal sealed class ArchiHandler : ClientMsgHandler {
internal const byte MaxGamesPlayedConcurrently = 32; // This is limit introduced by Steam Network
private readonly ArchiLogger ArchiLogger; private readonly ArchiLogger ArchiLogger;
internal ArchiHandler(ArchiLogger archiLogger) { internal ArchiHandler(ArchiLogger archiLogger) {

View file

@ -79,6 +79,10 @@
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath> <HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Humanizer, Version=2.1.0.0, Culture=neutral, PublicKeyToken=979442b78dfc278e, processorArchitecture=MSIL">
<HintPath>..\packages\Humanizer.Core.2.1.0\lib\netstandard1.0\Humanizer.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.2-beta1\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.9.0.2-beta1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private> <Private>True</Private>

View file

@ -2039,7 +2039,7 @@ namespace ArchiSteamFarm {
gamesToPlay.Add(gameID); gamesToPlay.Add(gameID);
if (gamesToPlay.Count >= CardsFarmer.MaxGamesPlayedConcurrently) { if (gamesToPlay.Count >= ArchiHandler.MaxGamesPlayedConcurrently) {
break; break;
} }
} }
@ -2368,7 +2368,7 @@ namespace ArchiSteamFarm {
response.Append("appIDs " + string.Join(", ", CardsFarmer.CurrentGamesFarming.Select(game => game.AppID))); response.Append("appIDs " + string.Join(", ", CardsFarmer.CurrentGamesFarming.Select(game => game.AppID)));
} }
response.Append(" and has a total of " + CardsFarmer.GamesToFarm.Count + " games (" + CardsFarmer.GamesToFarm.Sum(game => game.CardsRemaining) + " cards) left to farm."); response.Append(" and has a total of " + CardsFarmer.GamesToFarm.Count + " games (" + CardsFarmer.GamesToFarm.Sum(game => game.CardsRemaining) + " cards, about " + CardsFarmer.TimeRemaining.ToHumanReadable() + ") left to farm.");
return response.ToString(); return response.ToString();
} }

View file

@ -152,13 +152,13 @@ namespace ArchiSteamFarm {
// User might not know what he's doing // User might not know what he's doing
// Ensure that he can't screw core ASF variables // Ensure that he can't screw core ASF variables
if (botConfig.GamesPlayedWhileIdle.Count <= CardsFarmer.MaxGamesPlayedConcurrently) { if (botConfig.GamesPlayedWhileIdle.Count <= ArchiHandler.MaxGamesPlayedConcurrently) {
return botConfig; return botConfig;
} }
Program.ArchiLogger.LogGenericWarning("Playing more than " + CardsFarmer.MaxGamesPlayedConcurrently + " games concurrently is not possible, only first " + CardsFarmer.MaxGamesPlayedConcurrently + " entries from GamesPlayedWhileIdle will be used"); Program.ArchiLogger.LogGenericWarning("Playing more than " + ArchiHandler.MaxGamesPlayedConcurrently + " games concurrently is not possible, only first " + ArchiHandler.MaxGamesPlayedConcurrently + " entries from GamesPlayedWhileIdle will be used");
HashSet<uint> validGames = new HashSet<uint>(botConfig.GamesPlayedWhileIdle.Take(CardsFarmer.MaxGamesPlayedConcurrently)); HashSet<uint> validGames = new HashSet<uint>(botConfig.GamesPlayedWhileIdle.Take(ArchiHandler.MaxGamesPlayedConcurrently));
botConfig.GamesPlayedWhileIdle.IntersectWith(validGames); botConfig.GamesPlayedWhileIdle.IntersectWith(validGames);
botConfig.GamesPlayedWhileIdle.TrimExcess(); botConfig.GamesPlayedWhileIdle.TrimExcess();

View file

@ -34,7 +34,7 @@ using Newtonsoft.Json;
namespace ArchiSteamFarm { namespace ArchiSteamFarm {
internal sealed class CardsFarmer : IDisposable { internal sealed class CardsFarmer : IDisposable {
internal const byte MaxGamesPlayedConcurrently = 32; // This is limit introduced by Steam Network private const byte HoursToBump = 2; // How many hours are required for restricted accounts
private static readonly HashSet<uint> UntrustedAppIDs = new HashSet<uint> { 440, 570, 730 }; private static readonly HashSet<uint> UntrustedAppIDs = new HashSet<uint> { 440, 570, 730 };
@ -56,6 +56,13 @@ namespace ArchiSteamFarm {
private bool NowFarming; private bool NowFarming;
private bool StickyPause; private bool StickyPause;
[JsonProperty]
internal TimeSpan TimeRemaining => new TimeSpan(
Bot.BotConfig.CardDropsRestricted ? (int) Math.Ceiling(GamesToFarm.Count / (float) ArchiHandler.MaxGamesPlayedConcurrently * HoursToBump) : 0,
30 * GamesToFarm.Sum(game => game.CardsRemaining),
0
);
internal CardsFarmer(Bot bot) { internal CardsFarmer(Bot bot) {
if (bot == null) { if (bot == null) {
throw new ArgumentNullException(nameof(bot)); throw new ArgumentNullException(nameof(bot));
@ -95,8 +102,8 @@ namespace ArchiSteamFarm {
// If we have Complex algorithm and some games to boost, it's also worth to make a re-check, but only in this case // If we have Complex algorithm and some games to boost, it's also worth to make a re-check, but only in this case
// That's because we would check for new games after our current round anyway, and having extra games in the queue right away doesn't change anything // That's because we would check for new games after our current round anyway, and having extra games in the queue right away doesn't change anything
// Therefore, there is no need for extra restart of CardsFarmer if we have no games under 2 hours in current round // Therefore, there is no need for extra restart of CardsFarmer if we have no games under HoursToBump hours in current round
if (Bot.BotConfig.CardDropsRestricted && (GamesToFarm.Count > 0) && (GamesToFarm.Min(game => game.HoursPlayed) < 2)) { if (Bot.BotConfig.CardDropsRestricted && (GamesToFarm.Count > 0) && (GamesToFarm.Min(game => game.HoursPlayed) < HoursToBump)) {
await StopFarming().ConfigureAwait(false); await StopFarming().ConfigureAwait(false);
StartFarming().Forget(); StartFarming().Forget();
} }
@ -165,7 +172,7 @@ namespace ArchiSteamFarm {
return; return;
} }
Bot.ArchiLogger.LogGenericInfo("We have a total of " + GamesToFarm.Count + " games (" + GamesToFarm.Sum(game => game.CardsRemaining) + " cards) to farm on this account..."); Bot.ArchiLogger.LogGenericInfo("We have a total of " + GamesToFarm.Count + " games (" + GamesToFarm.Sum(game => game.CardsRemaining) + " cards, about " + TimeRemaining.ToHumanReadable() + ") to farm on this account...");
// This is the last moment for final check if we can farm // This is the last moment for final check if we can farm
if (!Bot.IsPlayingPossible) { if (!Bot.IsPlayingPossible) {
@ -183,7 +190,7 @@ namespace ArchiSteamFarm {
if (Bot.BotConfig.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
Bot.ArchiLogger.LogGenericInfo("Chosen farming algorithm: Complex"); Bot.ArchiLogger.LogGenericInfo("Chosen farming algorithm: Complex");
while (GamesToFarm.Count > 0) { while (GamesToFarm.Count > 0) {
HashSet<Game> gamesToFarmSolo = GamesToFarm.Count > 1 ? new HashSet<Game>(GamesToFarm.Where(game => game.HoursPlayed >= 2)) : new HashSet<Game>(GamesToFarm); HashSet<Game> gamesToFarmSolo = GamesToFarm.Count > 1 ? new HashSet<Game>(GamesToFarm.Where(game => game.HoursPlayed >= HoursToBump)) : new HashSet<Game>(GamesToFarm);
if (gamesToFarmSolo.Count > 0) { if (gamesToFarmSolo.Count > 0) {
while (gamesToFarmSolo.Count > 0) { while (gamesToFarmSolo.Count > 0) {
Game game = gamesToFarmSolo.First(); Game game = gamesToFarmSolo.First();
@ -195,7 +202,7 @@ namespace ArchiSteamFarm {
} }
} }
} else { } else {
if (FarmMultiple(GamesToFarm.OrderByDescending(game => game.HoursPlayed).Take(MaxGamesPlayedConcurrently))) { if (FarmMultiple(GamesToFarm.OrderByDescending(game => game.HoursPlayed).Take(ArchiHandler.MaxGamesPlayedConcurrently))) {
Bot.ArchiLogger.LogGenericInfo("Done farming: " + string.Join(", ", GamesToFarm.Select(game => game.AppID))); Bot.ArchiLogger.LogGenericInfo("Done farming: " + string.Join(", ", GamesToFarm.Select(game => game.AppID)));
} else { } else {
NowFarming = false; NowFarming = false;
@ -533,8 +540,8 @@ namespace ArchiSteamFarm {
return false; return false;
} }
if (maxHour >= 2) { if (maxHour >= HoursToBump) {
Bot.ArchiLogger.LogGenericError("Received request for past-2h games!"); Bot.ArchiLogger.LogGenericError("Received request for already boosted games!");
return true; return true;
} }
@ -602,7 +609,7 @@ namespace ArchiSteamFarm {
GamesToFarm.Remove(game); GamesToFarm.Remove(game);
TimeSpan timeSpan = TimeSpan.FromHours(game.HoursPlayed); TimeSpan timeSpan = TimeSpan.FromHours(game.HoursPlayed);
Bot.ArchiLogger.LogGenericInfo("Done farming: " + game.AppID + " (" + game.GameName + ") after " + timeSpan.ToString(@"hh\:mm") + " hours of playtime!"); Bot.ArchiLogger.LogGenericInfo("Done farming: " + game.AppID + " (" + game.GameName + ") after " + timeSpan.ToHumanReadable() + " of playtime!");
return true; return true;
} }

View file

@ -27,6 +27,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Humanizer;
namespace ArchiSteamFarm { namespace ArchiSteamFarm {
internal static class Utilities { internal static class Utilities {
@ -71,5 +72,7 @@ namespace ArchiSteamFarm {
return Random.Next(maxWithout); return Random.Next(maxWithout);
} }
} }
internal static string ToHumanReadable(this TimeSpan timeSpan) => timeSpan.Humanize(3, true);
} }
} }

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Costura.Fody" version="2.0.0-beta0018" targetFramework="net461" developmentDependency="true" /> <package id="Costura.Fody" version="2.0.0-beta0018" targetFramework="net461" developmentDependency="true" />
<package id="Fody" version="1.30.0-beta01" targetFramework="net461" developmentDependency="true" /> <package id="Fody" version="1.30.0-beta01" targetFramework="net461" developmentDependency="true" />
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net461" /> <package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net461" />
<package id="Humanizer.Core" version="2.1.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="9.0.2-beta1" targetFramework="net461" /> <package id="Newtonsoft.Json" version="9.0.2-beta1" targetFramework="net461" />
<package id="NLog" version="5.0.0-beta03" targetFramework="net461" /> <package id="NLog" version="5.0.0-beta03" targetFramework="net461" />
<package id="protobuf-net" version="2.0.0.668" targetFramework="net45" /> <package id="protobuf-net" version="2.0.0.668" targetFramework="net45" />

View file

@ -4,4 +4,13 @@
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup> </startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="NLog" publicKeyToken="5120e14c03d0593c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration> </configuration>

View file

@ -48,6 +48,10 @@
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath> <HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Humanizer, Version=2.1.0.0, Culture=neutral, PublicKeyToken=979442b78dfc278e, processorArchitecture=MSIL">
<HintPath>..\packages\Humanizer.Core.2.1.0\lib\netstandard1.0\Humanizer.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.2-beta1\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.9.0.2-beta1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private> <Private>True</Private>

View file

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="Costura.Fody" version="2.0.0-beta0018" targetFramework="net461" developmentDependency="true" /> <package id="Costura.Fody" version="2.0.0-beta0018" targetFramework="net461" developmentDependency="true" />
<package id="Fody" version="1.30.0-beta01" targetFramework="net461" developmentDependency="true" /> <package id="Fody" version="1.30.0-beta01" targetFramework="net461" developmentDependency="true" />
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net461" /> <package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net461" />
<package id="Humanizer.Core" version="2.1.0" targetFramework="net461" />
<package id="Newtonsoft.Json" version="9.0.2-beta1" targetFramework="net461" /> <package id="Newtonsoft.Json" version="9.0.2-beta1" targetFramework="net461" />
<package id="NLog" version="5.0.0-beta03" targetFramework="net461" /> <package id="NLog" version="5.0.0-beta03" targetFramework="net461" />
<package id="NLog.Windows.Forms" version="4.2.3" targetFramework="net461" /> <package id="NLog.Windows.Forms" version="4.2.3" targetFramework="net461" />

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff