Compare commits

...

20 Commits

Author SHA1 Message Date
JustArchi
5d21cd3452 Misc 2016-12-30 13:10:09 +01:00
JustArchi
b316224af3 Misc 2016-12-30 13:02:49 +01:00
JustArchi
c210480231 Fix default LootableTypes not being possible to remove 2016-12-30 13:01:02 +01:00
JustArchi
a44d097d4e Bump 2016-12-30 07:39:44 +01:00
JustArchi
df1e83130d Fix duplicating of LootableTypes in CG 2016-12-30 03:17:35 +01:00
JustArchi
2f1b6311ac Use HttpTimeout for WCF timeout 2016-12-29 10:40:35 +01:00
JustArchi
2c1127e57b Change default LoginID
Various bad scripts and other bots use LoginID of 0, so we will use LoginID of 1242, or whatever else, as long as it's static
2016-12-27 17:44:00 +01:00
JustArchi
9722059bb0 Don't crash on SteamDirectory failure 2016-12-27 16:18:42 +01:00
JustArchi
cb077a2c4a Add minutes to human-readable TimeSpan, #387 2016-12-27 16:00:21 +01:00
JustArchi
fb21b225bc Bump 2016-12-26 23:57:12 +01:00
JustArchi
bff9f61664 Misc 2016-12-26 23:54:40 +01:00
JustArchi
63cfa1341b Remove Gift and Coupon from Steam EType
It doesn't make any sense when we're always asking for community items, no need for extra confusion, and code is also shorter.
This IS another breaking change for past configs, so if you're using pre-release you should adapt your configs. But if you're using pre-release, I guess you know that such things happen.
2016-12-26 23:53:51 +01:00
JustArchi
19d15f09ff Optimize references 2016-12-26 23:15:01 +01:00
JustArchi
cf21c2a815 Remove dependency on Humanizer 2016-12-26 23:08:27 +01:00
JustArchi
8639275ed8 Fix 2016-12-26 22:41:50 +01:00
JustArchi
ba3461b58f Packages update 2016-12-26 22:10:56 +01:00
JustArchi
c089e3007d Code cleanup 2016-12-26 22:09:59 +01:00
JustArchi
33edc81116 Add farming time approximation
Because @MaduRUDE asked nicely
2016-12-26 22:07:49 +01:00
JustArchi
9b56734bad Increase WCF timeouts
As @Ryzhehvost pointed on chat, default value of 1 minute can be too short for more expensive ASF commands.
Notice: Setting SendTimeout on server side doesn't really affect anything here, but was added for consistency
2016-12-26 15:59:47 +01:00
JustArchi
00374d0912 Bump 2016-12-25 08:03:25 +01:00
51 changed files with 10414 additions and 2667 deletions

View File

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

View File

@@ -84,7 +84,7 @@
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.0.0-beta03\lib\net45\NLog.dll</HintPath>
<HintPath>..\packages\NLog.5.0.0-beta04\lib\net45\NLog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="protobuf-net, Version=2.0.0.668, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">

View File

@@ -1002,10 +1002,6 @@ namespace ArchiSteamFarm {
switch (name) {
case "Booster Pack":
return Steam.Item.EType.BoosterPack;
case "Coupon":
return Steam.Item.EType.Coupon;
case "Gift":
return Steam.Item.EType.Gift;
case "Steam Gems":
return Steam.Item.EType.SteamGems;
default:

View File

@@ -43,7 +43,7 @@ namespace ArchiSteamFarm {
internal sealed class Bot : IDisposable {
private const ushort CallbackSleep = 500; // In miliseconds
private const byte FamilySharingInactivityMinutes = 5;
private const uint LoginID = 0; // This must be the same for all ASF bots and all ASF processes
private const uint LoginID = GlobalConfig.DefaultWCFPort; // This must be the same for all ASF bots and all ASF processes
private const ushort MaxSteamMessageLength = 2048;
internal static readonly ConcurrentDictionary<string, Bot> Bots = new ConcurrentDictionary<string, Bot>();
@@ -314,8 +314,13 @@ namespace ArchiSteamFarm {
// Normally we wouldn't need to do this, but there is a case where our list might be invalid or outdated
// Ensure that we always ask once for list of up-to-date servers, even if we have list saved
Program.ArchiLogger.LogGenericInfo("Initializing SteamDirectory...");
await SteamDirectory.Initialize(cellID).ConfigureAwait(false);
Program.ArchiLogger.LogGenericInfo("Done!");
try {
await SteamDirectory.Initialize(cellID).ConfigureAwait(false);
Program.ArchiLogger.LogGenericInfo("Done!");
} catch {
Program.ArchiLogger.LogGenericWarning("Could not initialize SteamDirectory, connecting with Steam Network might take much longer than usual!");
}
}
internal async Task LootIfNeeded() {
@@ -2039,7 +2044,7 @@ namespace ArchiSteamFarm {
gamesToPlay.Add(gameID);
if (gamesToPlay.Count >= CardsFarmer.MaxGamesPlayedConcurrently) {
if (gamesToPlay.Count >= ArchiHandler.MaxGamesPlayedConcurrently) {
break;
}
}
@@ -2368,7 +2373,7 @@ namespace ArchiSteamFarm {
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();
}

View File

@@ -72,7 +72,7 @@ namespace ArchiSteamFarm {
[JsonProperty(Required = Required.DisallowNull)]
internal readonly bool IsBotAccount = false;
[JsonProperty(Required = Required.DisallowNull)]
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
internal readonly HashSet<Steam.Item.EType> LootableTypes = new HashSet<Steam.Item.EType> { Steam.Item.EType.BoosterPack, Steam.Item.EType.FoilTradingCard, Steam.Item.EType.TradingCard };
[JsonProperty(Required = Required.DisallowNull)]
@@ -152,13 +152,13 @@ namespace ArchiSteamFarm {
// User might not know what he's doing
// Ensure that he can't screw core ASF variables
if (botConfig.GamesPlayedWhileIdle.Count <= CardsFarmer.MaxGamesPlayedConcurrently) {
if (botConfig.GamesPlayedWhileIdle.Count <= ArchiHandler.MaxGamesPlayedConcurrently) {
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.TrimExcess();

View File

@@ -34,7 +34,7 @@ using Newtonsoft.Json;
namespace ArchiSteamFarm {
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 };
@@ -44,6 +44,13 @@ namespace ArchiSteamFarm {
[JsonProperty]
internal readonly ConcurrentHashSet<Game> GamesToFarm = new ConcurrentHashSet<Game>();
[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
);
private readonly Bot Bot;
private readonly SemaphoreSlim FarmingSemaphore = new SemaphoreSlim(1);
private readonly ManualResetEventSlim FarmResetEvent = new ManualResetEventSlim(false);
@@ -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
// 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
if (Bot.BotConfig.CardDropsRestricted && (GamesToFarm.Count > 0) && (GamesToFarm.Min(game => game.HoursPlayed) < 2)) {
// 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) < HoursToBump)) {
await StopFarming().ConfigureAwait(false);
StartFarming().Forget();
}
@@ -165,7 +172,7 @@ namespace ArchiSteamFarm {
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
if (!Bot.IsPlayingPossible) {
@@ -183,7 +190,7 @@ namespace ArchiSteamFarm {
if (Bot.BotConfig.CardDropsRestricted) { // If we have restricted card drops, we use complex algorithm
Bot.ArchiLogger.LogGenericInfo("Chosen farming algorithm: Complex");
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) {
while (gamesToFarmSolo.Count > 0) {
Game game = gamesToFarmSolo.First();
@@ -195,7 +202,7 @@ namespace ArchiSteamFarm {
}
}
} 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)));
} else {
NowFarming = false;
@@ -533,8 +540,8 @@ namespace ArchiSteamFarm {
return false;
}
if (maxHour >= 2) {
Bot.ArchiLogger.LogGenericError("Received request for past-2h games!");
if (maxHour >= HoursToBump) {
Bot.ArchiLogger.LogGenericError("Received request for already boosted games!");
return true;
}
@@ -602,7 +609,7 @@ namespace ArchiSteamFarm {
GamesToFarm.Remove(game);
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;
}

View File

@@ -35,11 +35,11 @@ namespace ArchiSteamFarm {
[SuppressMessage("ReSharper", "ConvertToConstant.Global")]
internal sealed class GlobalConfig {
internal const byte DefaultHttpTimeout = 60;
internal const ushort DefaultWCFPort = 1242;
private const byte DefaultFarmingDelay = 15;
private const byte DefaultMaxFarmingTime = 10;
private const ProtocolType DefaultSteamProtocol = ProtocolType.Tcp;
private const ushort DefaultWCFPort = 1242;
// This is hardcoded blacklist which should not be possible to change
internal static readonly HashSet<uint> GlobalBlacklist = new HashSet<uint> { 267420, 303700, 335590, 368020, 425280, 480730, 566020 };
@@ -50,7 +50,7 @@ namespace ArchiSteamFarm {
[JsonProperty(Required = Required.DisallowNull)]
internal readonly bool AutoUpdates = true;
[JsonProperty(Required = Required.DisallowNull)]
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
internal readonly HashSet<uint> Blacklist = new HashSet<uint>(GlobalBlacklist);
[JsonProperty(Required = Required.DisallowNull)]

View File

@@ -360,9 +360,7 @@ namespace ArchiSteamFarm.JSON {
internal enum EType : byte {
Unknown,
BoosterPack,
Coupon,
Emoticon,
Gift,
FoilTradingCard,
ProfileBackground,
TradingCard,

View File

@@ -44,7 +44,7 @@ namespace ArchiSteamFarm {
internal const string ServiceDescription = "ASF is an application that allows you to farm steam cards using multiple steam accounts simultaneously.";
internal const string ServiceName = "ArchiSteamFarm";
internal const string StatisticsServer = "asf.justarchi.net";
internal const string VersionNumber = "2.2.0.0";
internal const string VersionNumber = "2.2.0.3";
internal static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
}

View File

@@ -27,6 +27,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
namespace ArchiSteamFarm {
internal static class Utilities {
@@ -71,5 +72,62 @@ namespace ArchiSteamFarm {
return Random.Next(maxWithout);
}
}
internal static string ToHumanReadable(this TimeSpan timeSpan) {
// It's really dirty, I'd appreciate a lot if C# offered nice TimeSpan formatting by default
// Normally I'd use third-party library like Humanizer, but using it only for this bit is not worth it
// Besides, ILRepack has problem merging it's library due to referencing System.Runtime
StringBuilder result = new StringBuilder();
if (timeSpan.Days > 0) {
result.Append(" " + timeSpan.Days + " day");
if (timeSpan.Days > 1) {
result.Append('s');
}
result.Append(',');
}
if (timeSpan.Hours > 0) {
result.Append(" " + timeSpan.Hours + " hour");
if (timeSpan.Hours > 1) {
result.Append('s');
}
result.Append(',');
}
if (timeSpan.Minutes > 0) {
result.Append(" " + timeSpan.Minutes + " minute");
if (timeSpan.Minutes > 1) {
result.Append('s');
}
result.Append(',');
}
if (timeSpan.Seconds > 0) {
result.Append(" " + timeSpan.Hours + " second");
if (timeSpan.Seconds > 1) {
result.Append('s');
}
result.Append(',');
}
if (result.Length <= 1) {
return "";
}
// Get rid of initial space
result.Remove(0, 1);
// Get rid of last comma
result.Length--;
return result.ToString();
}
}
}

View File

@@ -97,7 +97,15 @@ namespace ArchiSteamFarm {
Program.ArchiLogger.LogGenericInfo("Sending command: " + input + " to WCF server on " + URL + "...");
if (Client == null) {
Client = new Client(new NetTcpBinding { Security = { Mode = SecurityMode.None } }, new EndpointAddress(URL));
Client = new Client(
new NetTcpBinding {
// We use SecurityMode.None for Mono compatibility
// Yes, also on Windows, for Mono<->Windows communication
Security = { Mode = SecurityMode.None },
SendTimeout = new TimeSpan(0, 0, Program.GlobalConfig.HttpTimeout)
},
new EndpointAddress(URL)
);
}
return Client.HandleCommand(input);
@@ -112,7 +120,16 @@ namespace ArchiSteamFarm {
try {
ServiceHost = new ServiceHost(typeof(WCF), new Uri(URL));
ServiceHost.AddServiceEndpoint(typeof(IWCF), new NetTcpBinding { Security = { Mode = SecurityMode.None } }, string.Empty);
ServiceHost.AddServiceEndpoint(
typeof(IWCF),
new NetTcpBinding {
// We use SecurityMode.None for Mono compatibility
// Yes, also on Windows, for Mono<->Windows communication
Security = { Mode = SecurityMode.None },
SendTimeout = new TimeSpan(0, 0, Program.GlobalConfig.HttpTimeout)
},
string.Empty
);
ServiceHost.Open();
Program.ArchiLogger.LogGenericInfo("WCF server ready!");

View File

@@ -13,8 +13,8 @@
"IsBotAccount": false,
"LootableTypes": [
1,
5,
7
3,
5
],
"PasswordFormat": 0,
"Paused": false,

View File

@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<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="HtmlAgilityPack" version="1.4.9.5" 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-beta04" targetFramework="net461" />
<package id="protobuf-net" version="2.0.0.668" targetFramework="net45" />
<package id="SteamKit2" version="1.8.0" targetFramework="net461" />
</packages>

View File

@@ -78,7 +78,8 @@ namespace ConfigGenerator {
[JsonProperty(Required = Required.DisallowNull)]
public bool IsBotAccount { get; set; } = false;
[JsonProperty(Required = Required.DisallowNull)]
[Category("\tAdvanced")]
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
public List<Steam.Item.EType> LootableTypes { get; set; } = new List<Steam.Item.EType> { Steam.Item.EType.BoosterPack, Steam.Item.EType.FoilTradingCard, Steam.Item.EType.TradingCard };
[Category("\tAccess")]

View File

@@ -53,8 +53,8 @@ namespace ConfigGenerator {
[JsonProperty(Required = Required.DisallowNull)]
public bool AutoUpdates { get; set; } = true;
[JsonProperty(Required = Required.DisallowNull)]
public List<uint> Blacklist { get; set; } = new List<uint>();
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
public List<uint> Blacklist { get; set; } = new List<uint>(GlobalBlacklist);
[Category("\tDebugging")]
[JsonProperty(Required = Required.DisallowNull)]
@@ -126,7 +126,6 @@ namespace ConfigGenerator {
throw new ArgumentNullException(nameof(filePath));
}
Blacklist.AddRange(GlobalBlacklist);
Save();
}

View File

@@ -31,9 +31,7 @@ namespace ConfigGenerator.JSON {
internal enum EType : byte {
Unknown,
BoosterPack,
Coupon,
Emoticon,
Gift,
FoilTradingCard,
ProfileBackground,
TradingCard,

View File

@@ -4,4 +4,13 @@
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</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>

View File

@@ -53,7 +53,7 @@
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.0.0-beta03\lib\net45\NLog.dll</HintPath>
<HintPath>..\packages\NLog.5.0.0-beta04\lib\net45\NLog.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NLog.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">

View File

@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<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="HtmlAgilityPack" version="1.4.9.5" 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-beta04" targetFramework="net461" />
<package id="NLog.Windows.Forms" version="4.2.3" targetFramework="net461" />
<package id="protobuf-net" version="2.0.0.668" targetFramework="net461" />
<package id="SteamKit2" version="1.8.0" targetFramework="net461" />

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.