Various code improvements

This commit is contained in:
JustArchi 2017-11-12 20:38:20 +01:00
parent 5ad01e2da8
commit 6a7e71c672
3 changed files with 55 additions and 52 deletions

View file

@ -46,7 +46,7 @@ namespace ArchiSteamFarm {
private const string ISteamUserAuth = "ISteamUserAuth"; private const string ISteamUserAuth = "ISteamUserAuth";
private const string ITwoFactorService = "ITwoFactorService"; private const string ITwoFactorService = "ITwoFactorService";
private const byte MinSessionTTL = GlobalConfig.DefaultConnectionTimeout / 4; // Assume session is valid for at least that amount of seconds private const byte MinSessionTTL = GlobalConfig.DefaultConnectionTimeout / 6; // Assume session is valid for at least that amount of seconds
// We must use HTTPS for SteamCommunity, as http would make certain POST requests failing (trades) // We must use HTTPS for SteamCommunity, as http would make certain POST requests failing (trades)
private const string SteamCommunityHost = "steamcommunity.com"; private const string SteamCommunityHost = "steamcommunity.com";

View file

@ -133,10 +133,10 @@ namespace ArchiSteamFarm {
return; return;
} }
// 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 any game 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 to boost in the queue right away doesn't change anything in terms of performance
// Therefore, there is no need for extra restart of CardsFarmer if we have no games under HoursToBump hours in current round // Therefore, make extra restart of CardsFarmer only if we have at least one game under HoursUntilCardDrops in current round
if ((Bot.BotConfig.HoursUntilCardDrops > 0) && (GamesToFarm.Count > 0) && (GamesToFarm.Min(game => game.HoursPlayed) < Bot.BotConfig.HoursUntilCardDrops)) { if ((Bot.BotConfig.HoursUntilCardDrops > 0) && (GamesToFarm.Count > 0) && GamesToFarm.Any(game => game.HoursPlayed < Bot.BotConfig.HoursUntilCardDrops)) {
await StopFarming().ConfigureAwait(false); await StopFarming().ConfigureAwait(false);
await StartFarming().ConfigureAwait(false); await StartFarming().ConfigureAwait(false);
} }
@ -587,48 +587,56 @@ namespace ArchiSteamFarm {
if (Bot.BotConfig.HoursUntilCardDrops > 0) { if (Bot.BotConfig.HoursUntilCardDrops > 0) {
// If we have restricted card drops, we use complex algorithm // If we have restricted card drops, we use complex algorithm
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Complex")); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Complex"));
while (GamesToFarm.Count > 0) { while (GamesToFarm.Count > 0) {
HashSet<Game> gamesToCheck = new HashSet<Game>(GamesToFarm.Count > 1 ? GamesToFarm.Where(game => game.HoursPlayed >= Bot.BotConfig.HoursUntilCardDrops) : GamesToFarm); // Initially we're going to farm games that passed our HoursUntilCardDrops
// This block is almost identical to Simple algorithm, we just copy appropriate items from GamesToFarm into innerGamesToFarm
HashSet<Game> innerGamesToFarm = new HashSet<Game>(GamesToFarm.Where(game => game.HoursPlayed >= Bot.BotConfig.HoursUntilCardDrops));
if (gamesToCheck.Count > 0) { while (innerGamesToFarm.Count > 0) {
foreach (Game game in gamesToCheck) { Game game = innerGamesToFarm.First();
if (!await IsPlayableGame(game).ConfigureAwait(false)) {
GamesToFarm.Remove(game);
continue;
}
if (await FarmSolo(game).ConfigureAwait(false)) { if (!await IsPlayableGame(game).ConfigureAwait(false)) {
continue; GamesToFarm.Remove(game);
} innerGamesToFarm.Remove(game);
continue;
NowFarming = false;
return;
} }
continue; if (await FarmSolo(game).ConfigureAwait(false)) {
innerGamesToFarm.Remove(game);
continue;
}
NowFarming = false;
return;
} }
gamesToCheck = new HashSet<Game>(GamesToFarm.OrderByDescending(game => game.HoursPlayed)); // At this point we have no games past HoursUntilCardDrops anymore, so we're going to farm all other ones
HashSet<Game> playableGamesToFarmMultiple = new HashSet<Game>(); // In order to maximize efficiency, we'll take games that are closest to our HoursPlayed first
foreach (Game game in gamesToCheck) { // We must call ToList() here as we can't remove items while enumerating
foreach (Game game in GamesToFarm.OrderByDescending(game => game.HoursPlayed).ToList()) {
if (!await IsPlayableGame(game).ConfigureAwait(false)) { if (!await IsPlayableGame(game).ConfigureAwait(false)) {
GamesToFarm.Remove(game); GamesToFarm.Remove(game);
continue; continue;
} }
playableGamesToFarmMultiple.Add(game); innerGamesToFarm.Add(game);
if (playableGamesToFarmMultiple.Count >= ArchiHandler.MaxGamesPlayedConcurrently) {
// There is no need to check all games at once, allow maximum of MaxGamesPlayedConcurrently in this batch
if (innerGamesToFarm.Count >= ArchiHandler.MaxGamesPlayedConcurrently) {
break; break;
} }
} }
if (playableGamesToFarmMultiple.Count == 0) { // If we have no playable games to farm, we're done
if (innerGamesToFarm.Count == 0) {
break; break;
} }
if (await FarmMultiple(playableGamesToFarmMultiple).ConfigureAwait(false)) { // Otherwise, we farm our innerGamesToFarm batch until any game hits HoursUntilCardDrops
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingFinishedForGames, string.Join(", ", playableGamesToFarmMultiple.Select(game => game.AppID)))); if (await FarmMultiple(innerGamesToFarm).ConfigureAwait(false)) {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingFinishedForGames, string.Join(", ", innerGamesToFarm.Select(game => game.AppID))));
} else { } else {
NowFarming = false; NowFarming = false;
return; return;
@ -639,49 +647,46 @@ namespace ArchiSteamFarm {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Simple")); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Simple"));
while (GamesToFarm.Count > 0) { while (GamesToFarm.Count > 0) {
HashSet<Game> gamesToCheck = new HashSet<Game>(GamesToFarm); // In simple algorithm we're going to farm anything that is playable, regardless of hours
Game game = GamesToFarm.First();
foreach (Game game in gamesToCheck) { if (!await IsPlayableGame(game).ConfigureAwait(false)) {
if (!await IsPlayableGame(game).ConfigureAwait(false)) { GamesToFarm.Remove(game);
GamesToFarm.Remove(game); continue;
continue;
}
if (await FarmSolo(game).ConfigureAwait(false)) {
continue;
}
NowFarming = false;
return;
} }
if (await FarmSolo(game).ConfigureAwait(false)) {
continue;
}
NowFarming = false;
return;
} }
} }
} while ((await IsAnythingToFarm().ConfigureAwait(false)).GetValueOrDefault()); } while ((await IsAnythingToFarm().ConfigureAwait(false)).GetValueOrDefault());
CurrentGamesFarming.Clear();
NowFarming = false; NowFarming = false;
Bot.ArchiLogger.LogGenericInfo(Strings.IdlingFinished); Bot.ArchiLogger.LogGenericInfo(Strings.IdlingFinished);
await Bot.OnFarmingFinished(true).ConfigureAwait(false); await Bot.OnFarmingFinished(true).ConfigureAwait(false);
} }
private async Task<bool> Farm(Game game) { private async Task<bool> FarmCards(Game game) {
if (game == null) { if (game == null) {
Bot.ArchiLogger.LogNullError(nameof(game)); Bot.ArchiLogger.LogNullError(nameof(game));
return false; return false;
} }
bool success = true;
if (game.AppID != game.PlayableAppID) { if (game.AppID != game.PlayableAppID) {
Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningIdlingGameMismatch, game.AppID, game.GameName, game.PlayableAppID)); Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningIdlingGameMismatch, game.AppID, game.GameName, game.PlayableAppID));
} }
await Bot.IdleGames(game.PlayableAppID.ToEnumerable()).ConfigureAwait(false); await Bot.IdleGames(game.PlayableAppID.ToEnumerable()).ConfigureAwait(false);
bool success = true;
DateTime endFarmingDate = DateTime.UtcNow.AddHours(Program.GlobalConfig.MaxFarmingTime); DateTime endFarmingDate = DateTime.UtcNow.AddHours(Program.GlobalConfig.MaxFarmingTime);
bool? keepFarming = await ShouldFarm(game).ConfigureAwait(false); while ((DateTime.UtcNow < endFarmingDate) && (await ShouldFarm(game).ConfigureAwait(false)).GetValueOrDefault(true)) {
while (keepFarming.GetValueOrDefault(true) && (DateTime.UtcNow < endFarmingDate)) {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdling, game.AppID, game.GameName)); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdling, game.AppID, game.GameName));
DateTime startFarmingPeriod = DateTime.UtcNow; DateTime startFarmingPeriod = DateTime.UtcNow;
@ -695,8 +700,6 @@ namespace ArchiSteamFarm {
if (!success) { if (!success) {
break; break;
} }
keepFarming = await ShouldFarm(game).ConfigureAwait(false);
} }
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StoppedIdling, game.AppID, game.GameName)); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StoppedIdling, game.AppID, game.GameName));
@ -754,7 +757,7 @@ namespace ArchiSteamFarm {
return false; return false;
} }
CurrentGamesFarming.ReplaceWith(games); CurrentGamesFarming.UnionWith(games);
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.NowIdlingList, string.Join(", ", CurrentGamesFarming.Select(game => game.AppID)))); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.NowIdlingList, string.Join(", ", CurrentGamesFarming.Select(game => game.AppID))));
@ -773,7 +776,7 @@ namespace ArchiSteamFarm {
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.NowIdling, game.AppID, game.GameName)); Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.NowIdling, game.AppID, game.GameName));
bool result = await Farm(game).ConfigureAwait(false); bool result = await FarmCards(game).ConfigureAwait(false);
CurrentGamesFarming.Clear(); CurrentGamesFarming.Clear();
if (!result) { if (!result) {
@ -1001,7 +1004,7 @@ namespace ArchiSteamFarm {
return; return;
} }
// We must call ToList() here as we can't enumerate during replacing // We must call ToList() here as we can't replace items while enumerating
GamesToFarm.ReplaceWith(gamesToFarm.ToList()); GamesToFarm.ReplaceWith(gamesToFarm.ToList());
} }

View file

@ -116,7 +116,7 @@ namespace ArchiSteamFarm {
return true; return true;
} }
internal void ReplaceWith(IEnumerable<T> other) { private void ReplaceWith(IEnumerable<T> other) {
BackingCollection.Clear(); BackingCollection.Clear();
foreach (T item in other) { foreach (T item in other) {
BackingCollection[item] = true; BackingCollection[item] = true;