mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-22 17:28:37 +00:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ebf2bf891 | ||
|
|
ec2c78ea81 | ||
|
|
eb88814c72 | ||
|
|
a28ad1fdac | ||
|
|
d36eaebbfe | ||
|
|
55067c669e | ||
|
|
9d882784ee | ||
|
|
829bd8ce2f | ||
|
|
532808c65d | ||
|
|
cc317e10a8 | ||
|
|
8aaee38a85 | ||
|
|
30c69cf57c | ||
|
|
4219107d2b | ||
|
|
ea89ef6696 | ||
|
|
4b1fc7ae56 | ||
|
|
6038faaa5f | ||
|
|
e3f87e4a19 | ||
|
|
90d74de169 | ||
|
|
b781195b77 | ||
|
|
c74d4c857e | ||
|
|
f1e67ee333 | ||
|
|
8d89095670 | ||
|
|
7fe65144c1 | ||
|
|
4404874e52 | ||
|
|
a1cf8c91c2 | ||
|
|
b7eac82596 | ||
|
|
b73bdee5af | ||
|
|
51ce849aee | ||
|
|
78af201cdb | ||
|
|
a580b6ab61 | ||
|
|
3cb24e19d9 | ||
|
|
399d438f8d | ||
|
|
00fb1b7c69 | ||
|
|
f477b79fa2 | ||
|
|
8ead6be751 | ||
|
|
e7912a05e7 | ||
|
|
1bb19415d4 | ||
|
|
aa063425ce | ||
|
|
e5a39cc0de | ||
|
|
6460918bdc | ||
|
|
0d2f3f09b0 | ||
|
|
711d573e28 | ||
|
|
e90780ddac | ||
|
|
cf4e9172ee | ||
|
|
9d0cc07d4e | ||
|
|
8eeab55d0b | ||
|
|
31387fe6a1 | ||
|
|
556a56f2d3 | ||
|
|
82a992ee9c | ||
|
|
be01239114 | ||
|
|
7b74577ce0 | ||
|
|
99cc57616c | ||
|
|
0af6d48a3c | ||
|
|
bbe38e34ee | ||
|
|
e937579c46 | ||
|
|
ac69473fb3 | ||
|
|
fb1f2910dd | ||
|
|
1a917a668c | ||
|
|
065d29177a | ||
|
|
b5cc74ca42 | ||
|
|
24ad984568 | ||
|
|
d48e0b06b6 | ||
|
|
cb0d1c9484 | ||
|
|
c75d99eb86 |
@@ -15,6 +15,7 @@ matrix:
|
|||||||
- mono: weekly
|
- mono: weekly
|
||||||
# - mono: alpha
|
# - mono: alpha
|
||||||
# - mono: beta
|
# - mono: beta
|
||||||
|
- mono: latest
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- source mono_envsetup.sh
|
- source mono_envsetup.sh
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ using ArchiSteamFarm.JSON;
|
|||||||
|
|
||||||
namespace ArchiSteamFarm {
|
namespace ArchiSteamFarm {
|
||||||
internal static class ASF {
|
internal static class ASF {
|
||||||
internal static readonly ArchiLogger ArchiLogger = new ArchiLogger(SharedInfo.ASF);
|
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<Bot, DateTime> LastWriteTimes = new ConcurrentDictionary<Bot, DateTime>();
|
private static readonly ConcurrentDictionary<Bot, DateTime> LastWriteTimes = new ConcurrentDictionary<Bot, DateTime>();
|
||||||
|
|
||||||
private static Timer AutoUpdatesTimer;
|
private static Timer AutoUpdatesTimer;
|
||||||
@@ -44,7 +42,7 @@ namespace ArchiSteamFarm {
|
|||||||
internal static async Task CheckForUpdate(bool updateOverride = false) {
|
internal static async Task CheckForUpdate(bool updateOverride = false) {
|
||||||
string exeFile = Assembly.GetEntryAssembly().Location;
|
string exeFile = Assembly.GetEntryAssembly().Location;
|
||||||
if (string.IsNullOrEmpty(exeFile)) {
|
if (string.IsNullOrEmpty(exeFile)) {
|
||||||
ArchiLogger.LogNullError(nameof(exeFile));
|
Program.ArchiLogger.LogNullError(nameof(exeFile));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,8 +56,8 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
File.Delete(oldExeFile);
|
File.Delete(oldExeFile);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
ArchiLogger.LogGenericError("Could not remove old ASF binary, please remove " + oldExeFile + " manually in order for update function to work!");
|
Program.ArchiLogger.LogGenericError("Could not remove old ASF binary, please remove " + oldExeFile + " manually in order for update function to work!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +70,7 @@ namespace ArchiSteamFarm {
|
|||||||
TimeSpan.FromDays(1) // Period
|
TimeSpan.FromDays(1) // Period
|
||||||
);
|
);
|
||||||
|
|
||||||
ArchiLogger.LogGenericInfo("ASF will automatically check for new versions every 24 hours");
|
Program.ArchiLogger.LogGenericInfo("ASF will automatically check for new versions every 24 hours");
|
||||||
}
|
}
|
||||||
|
|
||||||
string releaseURL = SharedInfo.GithubReleaseURL;
|
string releaseURL = SharedInfo.GithubReleaseURL;
|
||||||
@@ -80,20 +78,20 @@ namespace ArchiSteamFarm {
|
|||||||
releaseURL += "/latest";
|
releaseURL += "/latest";
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericInfo("Checking new version...");
|
Program.ArchiLogger.LogGenericInfo("Checking new version...");
|
||||||
|
|
||||||
GitHub.ReleaseResponse releaseResponse;
|
GitHub.ReleaseResponse releaseResponse;
|
||||||
|
|
||||||
if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) {
|
if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) {
|
||||||
releaseResponse = await Program.WebBrowser.UrlGetToJsonResultRetry<GitHub.ReleaseResponse>(releaseURL).ConfigureAwait(false);
|
releaseResponse = await Program.WebBrowser.UrlGetToJsonResultRetry<GitHub.ReleaseResponse>(releaseURL).ConfigureAwait(false);
|
||||||
if (releaseResponse == null) {
|
if (releaseResponse == null) {
|
||||||
ArchiLogger.LogGenericWarning("Could not check latest version!");
|
Program.ArchiLogger.LogGenericWarning("Could not check latest version!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
List<GitHub.ReleaseResponse> releases = await Program.WebBrowser.UrlGetToJsonResultRetry<List<GitHub.ReleaseResponse>>(releaseURL).ConfigureAwait(false);
|
List<GitHub.ReleaseResponse> releases = await Program.WebBrowser.UrlGetToJsonResultRetry<List<GitHub.ReleaseResponse>>(releaseURL).ConfigureAwait(false);
|
||||||
if ((releases == null) || (releases.Count == 0)) {
|
if ((releases == null) || (releases.Count == 0)) {
|
||||||
ArchiLogger.LogGenericWarning("Could not check latest version!");
|
Program.ArchiLogger.LogGenericWarning("Could not check latest version!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,33 +99,33 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(releaseResponse.Tag)) {
|
if (string.IsNullOrEmpty(releaseResponse.Tag)) {
|
||||||
ArchiLogger.LogGenericWarning("Could not check latest version!");
|
Program.ArchiLogger.LogGenericWarning("Could not check latest version!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Version newVersion = new Version(releaseResponse.Tag);
|
Version newVersion = new Version(releaseResponse.Tag);
|
||||||
|
|
||||||
ArchiLogger.LogGenericInfo("Local version: " + SharedInfo.Version + " | Remote version: " + newVersion);
|
Program.ArchiLogger.LogGenericInfo("Local version: " + SharedInfo.Version + " | Remote version: " + newVersion);
|
||||||
|
|
||||||
if (SharedInfo.Version.CompareTo(newVersion) >= 0) { // If local version is the same or newer than remote version
|
if (SharedInfo.Version.CompareTo(newVersion) >= 0) { // If local version is the same or newer than remote version
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!updateOverride && !Program.GlobalConfig.AutoUpdates) {
|
if (!updateOverride && !Program.GlobalConfig.AutoUpdates) {
|
||||||
ArchiLogger.LogGenericInfo("New version is available!");
|
Program.ArchiLogger.LogGenericInfo("New version is available!");
|
||||||
ArchiLogger.LogGenericInfo("Consider updating yourself!");
|
Program.ArchiLogger.LogGenericInfo("Consider updating yourself!");
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (File.Exists(oldExeFile)) {
|
if (File.Exists(oldExeFile)) {
|
||||||
ArchiLogger.LogGenericWarning("Refusing to proceed with auto update as old " + oldExeFile + " binary could not be removed, please remove it manually");
|
Program.ArchiLogger.LogGenericWarning("Refusing to proceed with auto update as old " + oldExeFile + " binary could not be removed, please remove it manually");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto update logic starts here
|
// Auto update logic starts here
|
||||||
if (releaseResponse.Assets == null) {
|
if (releaseResponse.Assets == null) {
|
||||||
ArchiLogger.LogGenericWarning("Could not proceed with update because that version doesn't include assets!");
|
Program.ArchiLogger.LogGenericWarning("Could not proceed with update because that version doesn't include assets!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,17 +133,17 @@ namespace ArchiSteamFarm {
|
|||||||
GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(exeFileName, StringComparison.OrdinalIgnoreCase));
|
GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(exeFileName, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
if (binaryAsset == null) {
|
if (binaryAsset == null) {
|
||||||
ArchiLogger.LogGenericWarning("Could not proceed with update because there is no asset that relates to currently running binary!");
|
Program.ArchiLogger.LogGenericWarning("Could not proceed with update because there is no asset that relates to currently running binary!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) {
|
if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) {
|
||||||
ArchiLogger.LogGenericWarning("Could not proceed with update because download URL is empty!");
|
Program.ArchiLogger.LogGenericWarning("Could not proceed with update because download URL is empty!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericInfo("Downloading new version...");
|
Program.ArchiLogger.LogGenericInfo("Downloading new version...");
|
||||||
ArchiLogger.LogGenericInfo("While waiting, consider donating if you appreciate the work being done :)");
|
Program.ArchiLogger.LogGenericInfo("While waiting, consider donating if you appreciate the work being done :)");
|
||||||
|
|
||||||
byte[] result = await Program.WebBrowser.UrlGetToBytesRetry(binaryAsset.DownloadURL).ConfigureAwait(false);
|
byte[] result = await Program.WebBrowser.UrlGetToBytesRetry(binaryAsset.DownloadURL).ConfigureAwait(false);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
@@ -158,7 +156,7 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
File.WriteAllBytes(newExeFile, result);
|
File.WriteAllBytes(newExeFile, result);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +164,7 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
File.Move(exeFile, oldExeFile);
|
File.Move(exeFile, oldExeFile);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
try {
|
try {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
File.Delete(newExeFile);
|
File.Delete(newExeFile);
|
||||||
@@ -180,7 +178,7 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
File.Move(newExeFile, exeFile);
|
File.Move(newExeFile, exeFile);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
try {
|
try {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
File.Move(oldExeFile, exeFile);
|
File.Move(oldExeFile, exeFile);
|
||||||
@@ -191,26 +189,17 @@ namespace ArchiSteamFarm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericInfo("Update process finished!");
|
Program.ArchiLogger.LogGenericInfo("Update process finished!");
|
||||||
|
await RestartOrExit().ConfigureAwait(false);
|
||||||
if (Program.GlobalConfig.AutoRestart) {
|
|
||||||
ArchiLogger.LogGenericInfo("Restarting...");
|
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
|
||||||
Program.Restart();
|
|
||||||
} else {
|
|
||||||
ArchiLogger.LogGenericInfo("Exiting...");
|
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
|
||||||
Program.Exit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void InitBots() {
|
internal static async Task InitBots() {
|
||||||
if (Bot.Bots.Count != 0) {
|
if (Bot.Bots.Count != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before attempting to connect, initialize our list of CMs
|
// Before attempting to connect, initialize our list of CMs
|
||||||
Bot.InitializeCMs(Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider);
|
await Bot.InitializeCMs(Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider).ConfigureAwait(false);
|
||||||
|
|
||||||
foreach (string botName in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*.json").Select(Path.GetFileNameWithoutExtension)) {
|
foreach (string botName in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*.json").Select(Path.GetFileNameWithoutExtension)) {
|
||||||
switch (botName) {
|
switch (botName) {
|
||||||
@@ -224,7 +213,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Bot.Bots.Count == 0) {
|
if (Bot.Bots.Count == 0) {
|
||||||
ArchiLogger.LogGenericWarning("No bots are defined, did you forget to configure your ASF?");
|
Program.ArchiLogger.LogGenericWarning("No bots are defined, did you forget to configure your ASF?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +236,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task CreateBot(string botName) {
|
private static async Task CreateBot(string botName) {
|
||||||
if (string.IsNullOrEmpty(botName)) {
|
if (string.IsNullOrEmpty(botName)) {
|
||||||
ArchiLogger.LogNullError(nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(botName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +256,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async void OnChanged(object sender, FileSystemEventArgs e) {
|
private static async void OnChanged(object sender, FileSystemEventArgs e) {
|
||||||
if ((sender == null) || (e == null)) {
|
if ((sender == null) || (e == null)) {
|
||||||
ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
Program.ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,8 +266,8 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (botName.Equals(SharedInfo.ASF)) {
|
if (botName.Equals(SharedInfo.ASF)) {
|
||||||
ArchiLogger.LogGenericError("Global config file has been changed, restarting...");
|
Program.ArchiLogger.LogGenericWarning("Global config file has been changed!");
|
||||||
Program.Restart();
|
await RestartOrExit().ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +308,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static void OnCreated(object sender, FileSystemEventArgs e) {
|
private static void OnCreated(object sender, FileSystemEventArgs e) {
|
||||||
if ((sender == null) || (e == null)) {
|
if ((sender == null) || (e == null)) {
|
||||||
ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
Program.ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +322,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static void OnDeleted(object sender, FileSystemEventArgs e) {
|
private static void OnDeleted(object sender, FileSystemEventArgs e) {
|
||||||
if ((sender == null) || (e == null)) {
|
if ((sender == null) || (e == null)) {
|
||||||
ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
Program.ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +332,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (botName.Equals(SharedInfo.ASF)) {
|
if (botName.Equals(SharedInfo.ASF)) {
|
||||||
ArchiLogger.LogGenericError("Global config file has been removed, exiting...");
|
Program.ArchiLogger.LogGenericError("Global config file has been removed, exiting...");
|
||||||
Program.Exit(1);
|
Program.Exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -356,7 +345,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static void OnRenamed(object sender, RenamedEventArgs e) {
|
private static void OnRenamed(object sender, RenamedEventArgs e) {
|
||||||
if ((sender == null) || (e == null)) {
|
if ((sender == null) || (e == null)) {
|
||||||
ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
Program.ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,7 +355,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (oldBotName.Equals(SharedInfo.ASF)) {
|
if (oldBotName.Equals(SharedInfo.ASF)) {
|
||||||
ArchiLogger.LogGenericError("Global config file has been renamed, exiting...");
|
Program.ArchiLogger.LogGenericError("Global config file has been renamed, exiting...");
|
||||||
Program.Exit(1);
|
Program.Exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -384,6 +373,18 @@ namespace ArchiSteamFarm {
|
|||||||
CreateBot(newBotName).Forget();
|
CreateBot(newBotName).Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task RestartOrExit() {
|
||||||
|
if (Program.GlobalConfig.AutoRestart) {
|
||||||
|
Program.ArchiLogger.LogGenericInfo("Restarting...");
|
||||||
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
|
Program.Restart();
|
||||||
|
} else {
|
||||||
|
Program.ArchiLogger.LogGenericInfo("Exiting...");
|
||||||
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
|
Program.Exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal sealed class BotConfigEventArgs : EventArgs {
|
internal sealed class BotConfigEventArgs : EventArgs {
|
||||||
internal readonly BotConfig BotConfig;
|
internal readonly BotConfig BotConfig;
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ArchiSteamFarm.CMsgs;
|
||||||
using SteamKit2;
|
using SteamKit2;
|
||||||
using SteamKit2.Internal;
|
using SteamKit2.Internal;
|
||||||
|
|
||||||
@@ -75,6 +76,24 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void AcceptClanInvite(ulong clanID, bool accept) {
|
||||||
|
if (clanID == 0) {
|
||||||
|
ArchiLogger.LogNullError(nameof(clanID));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Client.IsConnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientMsg<CMsgClientClanInviteAction> request = new ClientMsg<CMsgClientClanInviteAction>();
|
||||||
|
|
||||||
|
request.Body.ClanID = clanID;
|
||||||
|
request.Body.AcceptInvite = accept;
|
||||||
|
|
||||||
|
Client.Send(request);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Remove me once https://github.com/SteamRE/SteamKit/issues/305 is fixed
|
// TODO: Remove me once https://github.com/SteamRE/SteamKit/issues/305 is fixed
|
||||||
internal void LogOnWithoutMachineID(SteamUser.LogOnDetails details) {
|
internal void LogOnWithoutMachineID(SteamUser.LogOnDetails details) {
|
||||||
if (details == null) {
|
if (details == null) {
|
||||||
@@ -150,11 +169,19 @@ namespace ArchiSteamFarm {
|
|||||||
ClientMsgProtobuf<CMsgClientGamesPlayed> request = new ClientMsgProtobuf<CMsgClientGamesPlayed>(EMsg.ClientGamesPlayed);
|
ClientMsgProtobuf<CMsgClientGamesPlayed> request = new ClientMsgProtobuf<CMsgClientGamesPlayed>(EMsg.ClientGamesPlayed);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(gameName)) {
|
if (!string.IsNullOrEmpty(gameName)) {
|
||||||
request.Body.games_played.Add(new CMsgClientGamesPlayed.GamePlayed { game_extra_info = gameName, game_id = new GameID { AppType = GameID.GameType.Shortcut, ModID = uint.MaxValue } });
|
request.Body.games_played.Add(new CMsgClientGamesPlayed.GamePlayed {
|
||||||
|
game_extra_info = gameName,
|
||||||
|
game_id = new GameID {
|
||||||
|
AppType = GameID.GameType.Shortcut,
|
||||||
|
ModID = uint.MaxValue
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (uint gameID in gameIDs.Where(gameID => gameID != 0)) {
|
foreach (uint gameID in gameIDs.Where(gameID => gameID != 0)) {
|
||||||
request.Body.games_played.Add(new CMsgClientGamesPlayed.GamePlayed { game_id = new GameID(gameID) });
|
request.Body.games_played.Add(new CMsgClientGamesPlayed.GamePlayed {
|
||||||
|
game_id = new GameID(gameID)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Client.Send(request);
|
Client.Send(request);
|
||||||
@@ -368,7 +395,7 @@ namespace ArchiSteamFarm {
|
|||||||
KeyValue receiptInfo = new KeyValue();
|
KeyValue receiptInfo = new KeyValue();
|
||||||
using (MemoryStream ms = new MemoryStream(msg.purchase_receipt_info)) {
|
using (MemoryStream ms = new MemoryStream(msg.purchase_receipt_info)) {
|
||||||
if (!receiptInfo.TryReadAsBinary(ms)) {
|
if (!receiptInfo.TryReadAsBinary(ms)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(ms));
|
Program.ArchiLogger.LogNullError(nameof(ms));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,14 +412,14 @@ namespace ArchiSteamFarm {
|
|||||||
// Valid, coupons have PackageID of -1 (don't ask me why)
|
// Valid, coupons have PackageID of -1 (don't ask me why)
|
||||||
packageID = lineItem["ItemAppID"].AsUnsignedInteger();
|
packageID = lineItem["ItemAppID"].AsUnsignedInteger();
|
||||||
if (packageID == 0) {
|
if (packageID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(packageID));
|
Program.ArchiLogger.LogNullError(nameof(packageID));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string gameName = lineItem["ItemDescription"].Value;
|
string gameName = lineItem["ItemDescription"].Value;
|
||||||
if (string.IsNullOrEmpty(gameName)) {
|
if (string.IsNullOrEmpty(gameName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(gameName));
|
Program.ArchiLogger.LogNullError(nameof(gameName));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,15 @@ namespace ArchiSteamFarm {
|
|||||||
Logger.Debug($"{previousMethodName}() {message}");
|
Logger.Debug($"{previousMethodName}() {message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void LogGenericDebugException(Exception exception, [CallerMemberName] string previousMethodName = null) {
|
||||||
|
if (exception == null) {
|
||||||
|
LogNullError(nameof(exception));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Debug(exception, $"{previousMethodName}()");
|
||||||
|
}
|
||||||
|
|
||||||
internal void LogGenericError(string message, [CallerMemberName] string previousMethodName = null) {
|
internal void LogGenericError(string message, [CallerMemberName] string previousMethodName = null) {
|
||||||
if (string.IsNullOrEmpty(message)) {
|
if (string.IsNullOrEmpty(message)) {
|
||||||
LogNullError(nameof(message));
|
LogNullError(nameof(message));
|
||||||
|
|||||||
@@ -116,6 +116,7 @@
|
|||||||
<Compile Include="ASF.cs" />
|
<Compile Include="ASF.cs" />
|
||||||
<Compile Include="Bot.cs" />
|
<Compile Include="Bot.cs" />
|
||||||
<Compile Include="BotConfig.cs" />
|
<Compile Include="BotConfig.cs" />
|
||||||
|
<Compile Include="CMsgs\CMsgClientClanInviteAction.cs" />
|
||||||
<Compile Include="ConcurrentEnumerator.cs" />
|
<Compile Include="ConcurrentEnumerator.cs" />
|
||||||
<Compile Include="ConcurrentHashSet.cs" />
|
<Compile Include="ConcurrentHashSet.cs" />
|
||||||
<Compile Include="CryptoHelper.cs" />
|
<Compile Include="CryptoHelper.cs" />
|
||||||
@@ -137,6 +138,7 @@
|
|||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SharedInfo.cs" />
|
<Compile Include="SharedInfo.cs" />
|
||||||
<Compile Include="Statistics.cs" />
|
<Compile Include="Statistics.cs" />
|
||||||
|
<Compile Include="SteamSaleEvent.cs" />
|
||||||
<Compile Include="Trading.cs" />
|
<Compile Include="Trading.cs" />
|
||||||
<Compile Include="Utilities.cs" />
|
<Compile Include="Utilities.cs" />
|
||||||
<Compile Include="WCF.cs" />
|
<Compile Include="WCF.cs" />
|
||||||
|
|||||||
@@ -40,11 +40,15 @@ using Formatting = Newtonsoft.Json.Formatting;
|
|||||||
namespace ArchiSteamFarm {
|
namespace ArchiSteamFarm {
|
||||||
internal sealed class ArchiWebHandler : IDisposable {
|
internal sealed class ArchiWebHandler : IDisposable {
|
||||||
private const byte MinSessionTTL = GlobalConfig.DefaultHttpTimeout / 4; // Assume session is valid for at least that amount of seconds
|
private const byte MinSessionTTL = GlobalConfig.DefaultHttpTimeout / 4; // Assume session is valid for at least that amount of seconds
|
||||||
private const string SteamCommunityHost = "steamcommunity.com";
|
|
||||||
private const string SteamStoreHost = "store.steampowered.com";
|
|
||||||
|
|
||||||
private static string SteamCommunityURL = "https://" + SteamCommunityHost;
|
// We must use HTTPS for SteamCommunity, as http would make certain POST requests failing (trades)
|
||||||
private static string SteamStoreURL = "https://" + SteamStoreHost;
|
private const string SteamCommunityHost = "steamcommunity.com";
|
||||||
|
private const string SteamCommunityURL = "https://" + SteamCommunityHost;
|
||||||
|
|
||||||
|
// We could (and should) use HTTPS for SteamStore, but that would make certain POST requests failing
|
||||||
|
private const string SteamStoreHost = "store.steampowered.com";
|
||||||
|
private const string SteamStoreURL = "http://" + SteamStoreHost;
|
||||||
|
|
||||||
private static int Timeout = GlobalConfig.DefaultHttpTimeout * 1000; // This must be int type
|
private static int Timeout = GlobalConfig.DefaultHttpTimeout * 1000; // This must be int type
|
||||||
|
|
||||||
private readonly Bot Bot;
|
private readonly Bot Bot;
|
||||||
@@ -68,20 +72,20 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
public void Dispose() => SessionSemaphore.Dispose();
|
public void Dispose() => SessionSemaphore.Dispose();
|
||||||
|
|
||||||
internal async Task AcceptTradeOffer(ulong tradeID) {
|
internal async Task<bool> AcceptTradeOffer(ulong tradeID) {
|
||||||
if (tradeID == 0) {
|
if (tradeID == 0) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(tradeID));
|
Bot.ArchiLogger.LogNullError(nameof(tradeID));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
|
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
|
||||||
if (string.IsNullOrEmpty(sessionID)) {
|
if (string.IsNullOrEmpty(sessionID)) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(sessionID));
|
Bot.ArchiLogger.LogNullError(nameof(sessionID));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string referer = SteamCommunityURL + "/tradeoffer/" + tradeID;
|
string referer = SteamCommunityURL + "/tradeoffer/" + tradeID;
|
||||||
@@ -93,7 +97,7 @@ namespace ArchiSteamFarm {
|
|||||||
{ "tradeofferid", tradeID.ToString() }
|
{ "tradeofferid", tradeID.ToString() }
|
||||||
};
|
};
|
||||||
|
|
||||||
await WebBrowser.UrlPostRetry(request, data, referer).ConfigureAwait(false);
|
return await WebBrowser.UrlPostRetry(request, data, referer).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<bool> AddFreeLicense(uint subID) {
|
internal async Task<bool> AddFreeLicense(uint subID) {
|
||||||
@@ -112,7 +116,7 @@ namespace ArchiSteamFarm {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string request = SteamStoreURL + "/checkout/addfreelicense";
|
const string request = SteamStoreURL + "/checkout/addfreelicense";
|
||||||
Dictionary<string, string> data = new Dictionary<string, string>(3) {
|
Dictionary<string, string> data = new Dictionary<string, string>(3) {
|
||||||
{ "sessionid", sessionID },
|
{ "sessionid", sessionID },
|
||||||
{ "subid", subID.ToString() },
|
{ "subid", subID.ToString() },
|
||||||
@@ -123,6 +127,31 @@ namespace ArchiSteamFarm {
|
|||||||
return htmlDocument?.DocumentNode.SelectSingleNode("//div[@class='add_free_content_success_area']") != null;
|
return htmlDocument?.DocumentNode.SelectSingleNode("//div[@class='add_free_content_success_area']") != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal async Task<bool> ClearFromDiscoveryQueue(uint appID) {
|
||||||
|
if (appID == 0) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(appID));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamStoreURL, "sessionid");
|
||||||
|
if (string.IsNullOrEmpty(sessionID)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(sessionID));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string request = SteamStoreURL + "/app/" + appID;
|
||||||
|
Dictionary<string, string> data = new Dictionary<string, string>(2) {
|
||||||
|
{ "sessionid", sessionID },
|
||||||
|
{ "appid_to_clear_from_queue", appID.ToString() }
|
||||||
|
};
|
||||||
|
|
||||||
|
return await WebBrowser.UrlPostRetry(request, data).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
internal void DeclineTradeOffer(ulong tradeID) {
|
internal void DeclineTradeOffer(ulong tradeID) {
|
||||||
if ((tradeID == 0) || string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) {
|
if ((tradeID == 0) || string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(tradeID) + " || " + nameof(Bot.BotConfig.SteamApiKey));
|
Bot.ArchiLogger.LogNullError(nameof(tradeID) + " || " + nameof(Bot.BotConfig.SteamApiKey));
|
||||||
@@ -135,7 +164,11 @@ namespace ArchiSteamFarm {
|
|||||||
iEconService.Timeout = Timeout;
|
iEconService.Timeout = Timeout;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = iEconService.DeclineTradeOffer(tradeofferid: tradeID.ToString(), method: WebRequestMethods.Http.Post, secure: !Program.GlobalConfig.ForceHttp);
|
response = iEconService.DeclineTradeOffer(
|
||||||
|
tradeofferid: tradeID.ToString(),
|
||||||
|
method: WebRequestMethods.Http.Post,
|
||||||
|
secure: true
|
||||||
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Bot.ArchiLogger.LogGenericException(e);
|
Bot.ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
@@ -147,6 +180,27 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal async Task<HashSet<uint>> GenerateNewDiscoveryQueue() {
|
||||||
|
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamStoreURL, "sessionid");
|
||||||
|
if (string.IsNullOrEmpty(sessionID)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(sessionID));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string request = SteamStoreURL + "/explore/generatenewdiscoveryqueue";
|
||||||
|
Dictionary<string, string> data = new Dictionary<string, string>(2) {
|
||||||
|
{ "sessionid", sessionID },
|
||||||
|
{ "queuetype", "0" }
|
||||||
|
};
|
||||||
|
|
||||||
|
Steam.NewDiscoveryQueueResponse output = await WebBrowser.UrlPostToJsonResultRetry<Steam.NewDiscoveryQueueResponse>(request, data).ConfigureAwait(false);
|
||||||
|
return output?.Queue;
|
||||||
|
}
|
||||||
|
|
||||||
internal HashSet<Steam.TradeOffer> GetActiveTradeOffers() {
|
internal HashSet<Steam.TradeOffer> GetActiveTradeOffers() {
|
||||||
if (string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) {
|
if (string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(Bot.BotConfig.SteamApiKey));
|
Bot.ArchiLogger.LogNullError(nameof(Bot.BotConfig.SteamApiKey));
|
||||||
@@ -159,7 +213,12 @@ namespace ArchiSteamFarm {
|
|||||||
iEconService.Timeout = Timeout;
|
iEconService.Timeout = Timeout;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = iEconService.GetTradeOffers(get_received_offers: 1, active_only: 1, get_descriptions: 1, secure: !Program.GlobalConfig.ForceHttp);
|
response = iEconService.GetTradeOffers(
|
||||||
|
get_received_offers: 1,
|
||||||
|
active_only: 1,
|
||||||
|
get_descriptions: 1,
|
||||||
|
secure: true
|
||||||
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Bot.ArchiLogger.LogGenericException(e);
|
Bot.ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
@@ -301,12 +360,21 @@ namespace ArchiSteamFarm {
|
|||||||
return await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false);
|
return await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal async Task<HtmlDocument> GetDiscoveryQueuePage() {
|
||||||
|
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string request = SteamStoreURL + "/explore?l=english";
|
||||||
|
return await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
internal async Task<HashSet<ulong>> GetFamilySharingSteamIDs() {
|
internal async Task<HashSet<ulong>> GetFamilySharingSteamIDs() {
|
||||||
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
string request = SteamStoreURL + "/account/managedevices";
|
const string request = SteamStoreURL + "/account/managedevices";
|
||||||
HtmlDocument htmlDocument = await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false);
|
HtmlDocument htmlDocument = await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false);
|
||||||
|
|
||||||
HtmlNodeCollection htmlNodes = htmlDocument?.DocumentNode.SelectNodes("(//table[@class='accountTable'])[last()]//a/@data-miniprofile");
|
HtmlNodeCollection htmlNodes = htmlDocument?.DocumentNode.SelectNodes("(//table[@class='accountTable'])[last()]//a/@data-miniprofile");
|
||||||
@@ -349,7 +417,12 @@ namespace ArchiSteamFarm {
|
|||||||
return await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false);
|
return await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<HashSet<Steam.Item>> GetMySteamInventory(bool tradable) {
|
internal async Task<HashSet<Steam.Item>> GetMySteamInventory(bool tradable, HashSet<Steam.Item.EType> wantedTypes) {
|
||||||
|
if ((wantedTypes == null) || (wantedTypes.Count == 0)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(wantedTypes));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -445,6 +518,10 @@ namespace ArchiSteamFarm {
|
|||||||
steamItem.Type = description.Item2;
|
steamItem.Type = description.Item2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wantedTypes.Contains(steamItem.Type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
result.Add(steamItem);
|
result.Add(steamItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,7 +547,7 @@ namespace ArchiSteamFarm {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
string request = SteamCommunityURL + "/my/games/?xml=1";
|
const string request = SteamCommunityURL + "/my/games/?xml=1";
|
||||||
|
|
||||||
XmlDocument response = await WebBrowser.UrlGetToXMLRetry(request).ConfigureAwait(false);
|
XmlDocument response = await WebBrowser.UrlGetToXMLRetry(request).ConfigureAwait(false);
|
||||||
|
|
||||||
@@ -517,7 +594,11 @@ namespace ArchiSteamFarm {
|
|||||||
iPlayerService.Timeout = Timeout;
|
iPlayerService.Timeout = Timeout;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = iPlayerService.GetOwnedGames(steamid: steamID, include_appinfo: 1, secure: !Program.GlobalConfig.ForceHttp);
|
response = iPlayerService.GetOwnedGames(
|
||||||
|
steamid: steamID,
|
||||||
|
include_appinfo: 1,
|
||||||
|
secure: true
|
||||||
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Bot.ArchiLogger.LogGenericException(e);
|
Bot.ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
@@ -550,7 +631,10 @@ namespace ArchiSteamFarm {
|
|||||||
iTwoFactorService.Timeout = Timeout;
|
iTwoFactorService.Timeout = Timeout;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = iTwoFactorService.QueryTime(method: WebRequestMethods.Http.Post, secure: !Program.GlobalConfig.ForceHttp);
|
response = iTwoFactorService.QueryTime(
|
||||||
|
method: WebRequestMethods.Http.Post,
|
||||||
|
secure: true
|
||||||
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Bot.ArchiLogger.LogGenericException(e);
|
Bot.ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
@@ -565,6 +649,15 @@ namespace ArchiSteamFarm {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal async Task<HtmlDocument> GetSteamAwardsPage() {
|
||||||
|
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string request = SteamStoreURL + "/SteamAwards?l=english";
|
||||||
|
return await WebBrowser.UrlGetToHtmlDocumentRetry(request).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
internal async Task<byte?> GetTradeHoldDuration(ulong tradeID) {
|
internal async Task<byte?> GetTradeHoldDuration(ulong tradeID) {
|
||||||
if (tradeID == 0) {
|
if (tradeID == 0) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(tradeID));
|
Bot.ArchiLogger.LogNullError(nameof(tradeID));
|
||||||
@@ -642,8 +735,7 @@ namespace ArchiSteamFarm {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
string request = SteamCommunityURL + "/mobileconf/multiajaxop";
|
const string request = SteamCommunityURL + "/mobileconf/multiajaxop";
|
||||||
|
|
||||||
List<KeyValuePair<string, string>> data = new List<KeyValuePair<string, string>>(7 + confirmations.Count * 2) {
|
List<KeyValuePair<string, string>> data = new List<KeyValuePair<string, string>>(7 + confirmations.Count * 2) {
|
||||||
new KeyValuePair<string, string>("op", accept ? "allow" : "cancel"),
|
new KeyValuePair<string, string>("op", accept ? "allow" : "cancel"),
|
||||||
new KeyValuePair<string, string>("p", deviceID),
|
new KeyValuePair<string, string>("p", deviceID),
|
||||||
@@ -663,11 +755,7 @@ namespace ArchiSteamFarm {
|
|||||||
return response?.Success;
|
return response?.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Init() {
|
internal static void Init() => Timeout = Program.GlobalConfig.HttpTimeout * 1000;
|
||||||
Timeout = Program.GlobalConfig.HttpTimeout * 1000;
|
|
||||||
SteamCommunityURL = (Program.GlobalConfig.ForceHttp ? "http://" : "https://") + SteamCommunityHost;
|
|
||||||
SteamStoreURL = (Program.GlobalConfig.ForceHttp ? "http://" : "https://") + SteamStoreHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal async Task<bool> Init(ulong steamID, EUniverse universe, string webAPIUserNonce, string parentalPin) {
|
internal async Task<bool> Init(ulong steamID, EUniverse universe, string webAPIUserNonce, string parentalPin) {
|
||||||
if ((steamID == 0) || (universe == EUniverse.Invalid) || string.IsNullOrEmpty(webAPIUserNonce) || string.IsNullOrEmpty(parentalPin)) {
|
if ((steamID == 0) || (universe == EUniverse.Invalid) || string.IsNullOrEmpty(webAPIUserNonce) || string.IsNullOrEmpty(parentalPin)) {
|
||||||
@@ -703,7 +791,13 @@ namespace ArchiSteamFarm {
|
|||||||
iSteamUserAuth.Timeout = Timeout;
|
iSteamUserAuth.Timeout = Timeout;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
authResult = iSteamUserAuth.AuthenticateUser(steamid: steamID, sessionkey: Encoding.ASCII.GetString(WebUtility.UrlEncodeToBytes(cryptedSessionKey, 0, cryptedSessionKey.Length)), encrypted_loginkey: Encoding.ASCII.GetString(WebUtility.UrlEncodeToBytes(cryptedLoginKey, 0, cryptedLoginKey.Length)), method: WebRequestMethods.Http.Post, secure: !Program.GlobalConfig.ForceHttp);
|
authResult = iSteamUserAuth.AuthenticateUser(
|
||||||
|
steamid: steamID,
|
||||||
|
sessionkey: Encoding.ASCII.GetString(WebUtility.UrlEncodeToBytes(cryptedSessionKey, 0, cryptedSessionKey.Length)),
|
||||||
|
encrypted_loginkey: Encoding.ASCII.GetString(WebUtility.UrlEncodeToBytes(cryptedLoginKey, 0, cryptedLoginKey.Length)),
|
||||||
|
method: WebRequestMethods.Http.Post,
|
||||||
|
secure: true
|
||||||
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Bot.ArchiLogger.LogGenericException(e);
|
Bot.ArchiLogger.LogGenericException(e);
|
||||||
return false;
|
return false;
|
||||||
@@ -780,7 +874,7 @@ namespace ArchiSteamFarm {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
string request = SteamCommunityURL + "/my/inventory";
|
const string request = SteamCommunityURL + "/my/inventory";
|
||||||
return await WebBrowser.UrlHeadRetry(request).ConfigureAwait(false);
|
return await WebBrowser.UrlHeadRetry(request).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,7 +890,7 @@ namespace ArchiSteamFarm {
|
|||||||
return ArchiHandler.PurchaseResponseCallback.EPurchaseResult.Timeout;
|
return ArchiHandler.PurchaseResponseCallback.EPurchaseResult.Timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
string request = SteamStoreURL + "/account/validatewalletcode";
|
const string request = SteamStoreURL + "/account/validatewalletcode";
|
||||||
Dictionary<string, string> data = new Dictionary<string, string>(1) {
|
Dictionary<string, string> data = new Dictionary<string, string>(1) {
|
||||||
{ "wallet_code", key }
|
{ "wallet_code", key }
|
||||||
};
|
};
|
||||||
@@ -840,8 +934,8 @@ namespace ArchiSteamFarm {
|
|||||||
itemID++;
|
itemID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
string referer = SteamCommunityURL + "/tradeoffer/new";
|
const string referer = SteamCommunityURL + "/tradeoffer/new";
|
||||||
string request = referer + "/send";
|
const string request = referer + "/send";
|
||||||
foreach (Dictionary<string, string> data in trades.Select(trade => new Dictionary<string, string>(6) {
|
foreach (Dictionary<string, string> data in trades.Select(trade => new Dictionary<string, string>(6) {
|
||||||
{ "sessionid", sessionID },
|
{ "sessionid", sessionID },
|
||||||
{ "serverid", "1" },
|
{ "serverid", "1" },
|
||||||
@@ -858,9 +952,35 @@ namespace ArchiSteamFarm {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal async Task<bool> SteamAwardsVote(byte voteID, uint appID) {
|
||||||
|
if ((voteID == 0) || (appID == 0)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(voteID) + " || " + nameof(appID));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamStoreURL, "sessionid");
|
||||||
|
if (string.IsNullOrEmpty(sessionID)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(sessionID));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const string request = SteamStoreURL + "/salevote";
|
||||||
|
Dictionary<string, string> data = new Dictionary<string, string>(3) {
|
||||||
|
{ "sessionid", sessionID },
|
||||||
|
{ "voteid", voteID.ToString() },
|
||||||
|
{ "appid", appID.ToString() }
|
||||||
|
};
|
||||||
|
|
||||||
|
return await WebBrowser.UrlPostRetry(request, data).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
private static uint GetAppIDFromMarketHashName(string hashName) {
|
private static uint GetAppIDFromMarketHashName(string hashName) {
|
||||||
if (string.IsNullOrEmpty(hashName)) {
|
if (string.IsNullOrEmpty(hashName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(hashName));
|
Program.ArchiLogger.LogNullError(nameof(hashName));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -875,7 +995,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static Steam.Item.EType GetItemType(string name) {
|
private static Steam.Item.EType GetItemType(string name) {
|
||||||
if (string.IsNullOrEmpty(name)) {
|
if (string.IsNullOrEmpty(name)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(name));
|
Program.ArchiLogger.LogNullError(nameof(name));
|
||||||
return Steam.Item.EType.Unknown;
|
return Steam.Item.EType.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -908,7 +1028,7 @@ namespace ArchiSteamFarm {
|
|||||||
private async Task<bool?> IsLoggedIn() {
|
private async Task<bool?> IsLoggedIn() {
|
||||||
// It would make sense to use /my/profile here, but it dismisses notifications related to profile comments
|
// It would make sense to use /my/profile here, but it dismisses notifications related to profile comments
|
||||||
// So instead, we'll use some less intrusive link, such as /my/videos
|
// So instead, we'll use some less intrusive link, such as /my/videos
|
||||||
string request = SteamCommunityURL + "/my/videos";
|
const string request = SteamCommunityURL + "/my/videos";
|
||||||
|
|
||||||
Uri uri = await WebBrowser.UrlHeadToUriRetry(request).ConfigureAwait(false);
|
Uri uri = await WebBrowser.UrlHeadToUriRetry(request).ConfigureAwait(false);
|
||||||
return !uri?.AbsolutePath.StartsWith("/login", StringComparison.Ordinal);
|
return !uri?.AbsolutePath.StartsWith("/login", StringComparison.Ordinal);
|
||||||
@@ -916,32 +1036,32 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static bool ParseItems(Dictionary<ulong, Tuple<uint, Steam.Item.EType>> descriptions, List<KeyValue> input, HashSet<Steam.Item> output) {
|
private static bool ParseItems(Dictionary<ulong, Tuple<uint, Steam.Item.EType>> descriptions, List<KeyValue> input, HashSet<Steam.Item> output) {
|
||||||
if ((descriptions == null) || (input == null) || (input.Count == 0) || (output == null)) {
|
if ((descriptions == null) || (input == null) || (input.Count == 0) || (output == null)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(descriptions) + " || " + nameof(input) + " || " + nameof(output));
|
Program.ArchiLogger.LogNullError(nameof(descriptions) + " || " + nameof(input) + " || " + nameof(output));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (KeyValue item in input) {
|
foreach (KeyValue item in input) {
|
||||||
uint appID = item["appid"].AsUnsignedInteger();
|
uint appID = item["appid"].AsUnsignedInteger();
|
||||||
if (appID == 0) {
|
if (appID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(appID));
|
Program.ArchiLogger.LogNullError(nameof(appID));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong contextID = item["contextid"].AsUnsignedLong();
|
ulong contextID = item["contextid"].AsUnsignedLong();
|
||||||
if (contextID == 0) {
|
if (contextID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(contextID));
|
Program.ArchiLogger.LogNullError(nameof(contextID));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong classID = item["classid"].AsUnsignedLong();
|
ulong classID = item["classid"].AsUnsignedLong();
|
||||||
if (classID == 0) {
|
if (classID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(classID));
|
Program.ArchiLogger.LogNullError(nameof(classID));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint amount = item["amount"].AsUnsignedInteger();
|
uint amount = item["amount"].AsUnsignedInteger();
|
||||||
if (amount == 0) {
|
if (amount == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(amount));
|
Program.ArchiLogger.LogNullError(nameof(amount));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -994,7 +1114,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
Bot.ArchiLogger.LogGenericInfo("Unlocking parental account...");
|
Bot.ArchiLogger.LogGenericInfo("Unlocking parental account...");
|
||||||
|
|
||||||
string request = SteamCommunityURL + "/parental/ajaxunlock";
|
const string request = SteamCommunityURL + "/parental/ajaxunlock";
|
||||||
Dictionary<string, string> data = new Dictionary<string, string>(1) {
|
Dictionary<string, string> data = new Dictionary<string, string>(1) {
|
||||||
{ "pin", parentalPin }
|
{ "pin", parentalPin }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -82,27 +82,32 @@ namespace ArchiSteamFarm {
|
|||||||
private readonly SteamClient SteamClient;
|
private readonly SteamClient SteamClient;
|
||||||
private readonly ConcurrentHashSet<ulong> SteamFamilySharingIDs = new ConcurrentHashSet<ulong>();
|
private readonly ConcurrentHashSet<ulong> SteamFamilySharingIDs = new ConcurrentHashSet<ulong>();
|
||||||
private readonly SteamFriends SteamFriends;
|
private readonly SteamFriends SteamFriends;
|
||||||
|
private readonly SteamSaleEvent SteamSaleEvent;
|
||||||
private readonly SteamUser SteamUser;
|
private readonly SteamUser SteamUser;
|
||||||
private readonly Trading Trading;
|
private readonly Trading Trading;
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
internal BotConfig BotConfig { get; private set; }
|
internal BotConfig BotConfig { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
internal bool IsLimitedUser { get; private set; }
|
internal bool IsLimitedUser { get; private set; }
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
internal bool KeepRunning { get; private set; }
|
internal bool KeepRunning { get; private set; }
|
||||||
|
|
||||||
private Timer AcceptConfirmationsTimer;
|
private Timer AcceptConfirmationsTimer;
|
||||||
private string AuthCode, TwoFactorCode;
|
private string AuthCode;
|
||||||
|
private Timer ConnectingTimeoutTimer;
|
||||||
private Timer FamilySharingInactivityTimer;
|
private Timer FamilySharingInactivityTimer;
|
||||||
private bool FirstTradeSent;
|
private bool FirstTradeSent;
|
||||||
private byte HeartBeatFailures;
|
private byte HeartBeatFailures;
|
||||||
private EResult LastLogOnResult;
|
private EResult LastLogOnResult;
|
||||||
private ulong LibraryLockedBySteamID;
|
private ulong LibraryLockedBySteamID;
|
||||||
|
private bool LootingAllowed = true;
|
||||||
private bool PlayingBlocked;
|
private bool PlayingBlocked;
|
||||||
private Timer SendItemsTimer;
|
private Timer SendItemsTimer;
|
||||||
private bool SkipFirstShutdown;
|
private bool SkipFirstShutdown;
|
||||||
|
private string TwoFactorCode;
|
||||||
|
|
||||||
internal Bot(string botName) {
|
internal Bot(string botName) {
|
||||||
if (string.IsNullOrEmpty(botName)) {
|
if (string.IsNullOrEmpty(botName)) {
|
||||||
@@ -203,13 +208,17 @@ namespace ArchiSteamFarm {
|
|||||||
CardsFarmer = new CardsFarmer(this);
|
CardsFarmer = new CardsFarmer(this);
|
||||||
CardsFarmer.SetInitialState(BotConfig.Paused);
|
CardsFarmer.SetInitialState(BotConfig.Paused);
|
||||||
|
|
||||||
|
SteamSaleEvent = new SteamSaleEvent(this);
|
||||||
Trading = new Trading(this);
|
Trading = new Trading(this);
|
||||||
|
|
||||||
if (Program.GlobalConfig.Statistics) {
|
if (Program.GlobalConfig.Statistics) {
|
||||||
Statistics = new Statistics(this);
|
Statistics = new Statistics(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
HeartBeatTimer = new Timer(async e => await HeartBeat().ConfigureAwait(false), null, TimeSpan.FromMinutes(1) + TimeSpan.FromMinutes(0.2 * Bots.Count), // Delay
|
HeartBeatTimer = new Timer(
|
||||||
|
async e => await HeartBeat().ConfigureAwait(false),
|
||||||
|
null,
|
||||||
|
TimeSpan.FromMinutes(1) + TimeSpan.FromMinutes(0.2 * Bots.Count), // Delay
|
||||||
TimeSpan.FromMinutes(1) // Period
|
TimeSpan.FromMinutes(1) // Period
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -226,10 +235,12 @@ namespace ArchiSteamFarm {
|
|||||||
InitializationSemaphore.Dispose();
|
InitializationSemaphore.Dispose();
|
||||||
SteamFamilySharingIDs.Dispose();
|
SteamFamilySharingIDs.Dispose();
|
||||||
OwnedPackageIDs.Dispose();
|
OwnedPackageIDs.Dispose();
|
||||||
|
SteamSaleEvent.Dispose();
|
||||||
Trading.Dispose();
|
Trading.Dispose();
|
||||||
|
|
||||||
// Those are objects that might be null and the check should be in-place
|
// Those are objects that might be null and the check should be in-place
|
||||||
AcceptConfirmationsTimer?.Dispose();
|
AcceptConfirmationsTimer?.Dispose();
|
||||||
|
ConnectingTimeoutTimer?.Dispose();
|
||||||
FamilySharingInactivityTimer?.Dispose();
|
FamilySharingInactivityTimer?.Dispose();
|
||||||
SendItemsTimer?.Dispose();
|
SendItemsTimer?.Dispose();
|
||||||
}
|
}
|
||||||
@@ -279,24 +290,32 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal static string GetAPIStatus() {
|
internal static string GetAPIStatus() {
|
||||||
var response = new { Bots };
|
var response = new {
|
||||||
|
Bots
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return JsonConvert.SerializeObject(response);
|
return JsonConvert.SerializeObject(response);
|
||||||
} catch (JsonException e) {
|
} catch (JsonException e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void InitializeCMs(uint cellID, IServerListProvider serverListProvider) {
|
internal static async Task InitializeCMs(uint cellID, IServerListProvider serverListProvider) {
|
||||||
if (serverListProvider == null) {
|
if (serverListProvider == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(serverListProvider));
|
Program.ArchiLogger.LogNullError(nameof(serverListProvider));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CMClient.Servers.CellID = cellID;
|
CMClient.Servers.CellID = cellID;
|
||||||
CMClient.Servers.ServerListProvider = serverListProvider;
|
CMClient.Servers.ServerListProvider = serverListProvider;
|
||||||
|
|
||||||
|
// 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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task LootIfNeeded() {
|
internal async Task LootIfNeeded() {
|
||||||
@@ -358,15 +377,18 @@ namespace ArchiSteamFarm {
|
|||||||
TimeSpan period = TimeSpan.FromMinutes(BotConfig.AcceptConfirmationsPeriod);
|
TimeSpan period = TimeSpan.FromMinutes(BotConfig.AcceptConfirmationsPeriod);
|
||||||
|
|
||||||
if (AcceptConfirmationsTimer == null) {
|
if (AcceptConfirmationsTimer == null) {
|
||||||
AcceptConfirmationsTimer = new Timer(async e => await AcceptConfirmations(true).ConfigureAwait(false), null, delay, // Delay
|
AcceptConfirmationsTimer = new Timer(
|
||||||
|
async e => await AcceptConfirmations(true).ConfigureAwait(false),
|
||||||
|
null,
|
||||||
|
delay, // Delay
|
||||||
period // Period
|
period // Period
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
AcceptConfirmationsTimer.Change(delay, period);
|
AcceptConfirmationsTimer.Change(delay, period);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (AcceptConfirmationsTimer != null) {
|
||||||
AcceptConfirmationsTimer?.Change(Timeout.Infinite, Timeout.Infinite);
|
AcceptConfirmationsTimer.Dispose();
|
||||||
AcceptConfirmationsTimer?.Dispose();
|
AcceptConfirmationsTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((BotConfig.SendTradePeriod > 0) && (BotConfig.SteamMasterID != 0)) {
|
if ((BotConfig.SendTradePeriod > 0) && (BotConfig.SteamMasterID != 0)) {
|
||||||
@@ -374,15 +396,18 @@ namespace ArchiSteamFarm {
|
|||||||
TimeSpan period = TimeSpan.FromHours(BotConfig.SendTradePeriod);
|
TimeSpan period = TimeSpan.FromHours(BotConfig.SendTradePeriod);
|
||||||
|
|
||||||
if (SendItemsTimer == null) {
|
if (SendItemsTimer == null) {
|
||||||
SendItemsTimer = new Timer(async e => await ResponseLoot(BotConfig.SteamMasterID).ConfigureAwait(false), null, delay, // Delay
|
SendItemsTimer = new Timer(
|
||||||
|
async e => await ResponseLoot(BotConfig.SteamMasterID).ConfigureAwait(false),
|
||||||
|
null,
|
||||||
|
delay, // Delay
|
||||||
period // Period
|
period // Period
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
SendItemsTimer.Change(delay, period);
|
SendItemsTimer.Change(delay, period);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (SendItemsTimer != null) {
|
||||||
SendItemsTimer?.Change(Timeout.Infinite, Timeout.Infinite);
|
SendItemsTimer.Dispose();
|
||||||
SendItemsTimer?.Dispose();
|
SendItemsTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Initialize().ConfigureAwait(false);
|
await Initialize().ConfigureAwait(false);
|
||||||
@@ -451,6 +476,8 @@ namespace ArchiSteamFarm {
|
|||||||
return ResponseHelp(steamID);
|
return ResponseHelp(steamID);
|
||||||
case "!LOOT":
|
case "!LOOT":
|
||||||
return await ResponseLoot(steamID).ConfigureAwait(false);
|
return await ResponseLoot(steamID).ConfigureAwait(false);
|
||||||
|
case "!LOOT^":
|
||||||
|
return ResponseLootSwitch(steamID);
|
||||||
case "!LOOTALL":
|
case "!LOOTALL":
|
||||||
return await ResponseLootAll(steamID).ConfigureAwait(false);
|
return await ResponseLootAll(steamID).ConfigureAwait(false);
|
||||||
case "!PASSWORD":
|
case "!PASSWORD":
|
||||||
@@ -500,6 +527,8 @@ namespace ArchiSteamFarm {
|
|||||||
return await ResponseFarm(steamID, args[1]).ConfigureAwait(false);
|
return await ResponseFarm(steamID, args[1]).ConfigureAwait(false);
|
||||||
case "!LOOT":
|
case "!LOOT":
|
||||||
return await ResponseLoot(steamID, args[1]).ConfigureAwait(false);
|
return await ResponseLoot(steamID, args[1]).ConfigureAwait(false);
|
||||||
|
case "!LOOT^":
|
||||||
|
return ResponseLootSwitch(steamID, args[1]);
|
||||||
case "!OWNS":
|
case "!OWNS":
|
||||||
if (args.Length > 2) {
|
if (args.Length > 2) {
|
||||||
return await ResponseOwns(steamID, args[1], args[2]).ConfigureAwait(false);
|
return await ResponseOwns(steamID, args[1], args[2]).ConfigureAwait(false);
|
||||||
@@ -577,6 +606,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericInfo("Shared library has not been launched in given time period, farming process resumed!");
|
ArchiLogger.LogGenericInfo("Shared library has not been launched in given time period, farming process resumed!");
|
||||||
|
StopFamilySharingInactivityTimer();
|
||||||
CardsFarmer.Resume(false);
|
CardsFarmer.Resume(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,6 +641,16 @@ namespace ArchiSteamFarm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ConnectingTimeoutTimer == null) {
|
||||||
|
ConnectingTimeoutTimer = new Timer(
|
||||||
|
async e => await Connect().ConfigureAwait(false),
|
||||||
|
null,
|
||||||
|
TimeSpan.FromMinutes(1), // Delay
|
||||||
|
TimeSpan.FromMinutes(1) // Period
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiLogger.LogGenericInfo("Connecting...");
|
||||||
SteamClient.Connect();
|
SteamClient.Connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -629,6 +669,11 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private void Disconnect() {
|
private void Disconnect() {
|
||||||
lock (SteamClient) {
|
lock (SteamClient) {
|
||||||
|
if (ConnectingTimeoutTimer != null) {
|
||||||
|
ConnectingTimeoutTimer.Dispose();
|
||||||
|
ConnectingTimeoutTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
SteamClient.Disconnect();
|
SteamClient.Disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -771,12 +816,21 @@ namespace ArchiSteamFarm {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsMasterClanID(ulong steamID) {
|
||||||
|
if (steamID != 0) {
|
||||||
|
return steamID == BotConfig.SteamMasterClanID;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchiLogger.LogNullError(nameof(steamID));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsOwner(ulong steamID) {
|
private static bool IsOwner(ulong steamID) {
|
||||||
if (steamID != 0) {
|
if (steamID != 0) {
|
||||||
return (steamID == Program.GlobalConfig.SteamOwnerID) || (Debugging.IsDebugBuild && (steamID == SharedInfo.ArchiSteamID));
|
return (steamID == Program.GlobalConfig.SteamOwnerID) || (Debugging.IsDebugBuild && (steamID == SharedInfo.ArchiSteamID));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
Program.ArchiLogger.LogNullError(nameof(steamID));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -785,7 +839,7 @@ namespace ArchiSteamFarm {
|
|||||||
return Regex.IsMatch(key, @"^[0-9A-Z]{4,7}-[0-9A-Z]{4,7}-[0-9A-Z]{4,7}(?:(?:-[0-9A-Z]{4,7})?(?:-[0-9A-Z]{4,7}))?$", RegexOptions.IgnoreCase);
|
return Regex.IsMatch(key, @"^[0-9A-Z]{4,7}-[0-9A-Z]{4,7}-[0-9A-Z]{4,7}(?:(?:-[0-9A-Z]{4,7})?(?:-[0-9A-Z]{4,7}))?$", RegexOptions.IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogNullError(nameof(key));
|
Program.ArchiLogger.LogNullError(nameof(key));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,6 +928,11 @@ namespace ArchiSteamFarm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ConnectingTimeoutTimer != null) {
|
||||||
|
ConnectingTimeoutTimer.Dispose();
|
||||||
|
ConnectingTimeoutTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (callback.Result != EResult.OK) {
|
if (callback.Result != EResult.OK) {
|
||||||
ArchiLogger.LogGenericError("Unable to connect to Steam: " + callback.Result);
|
ArchiLogger.LogGenericError("Unable to connect to Steam: " + callback.Result);
|
||||||
return;
|
return;
|
||||||
@@ -943,6 +1002,11 @@ namespace ArchiSteamFarm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ConnectingTimeoutTimer != null) {
|
||||||
|
ConnectingTimeoutTimer.Dispose();
|
||||||
|
ConnectingTimeoutTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
HeartBeatFailures = 0;
|
HeartBeatFailures = 0;
|
||||||
|
|
||||||
EResult lastLogOnResult = LastLogOnResult;
|
EResult lastLogOnResult = LastLogOnResult;
|
||||||
@@ -1057,10 +1121,18 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (SteamFriends.FriendsListCallback.Friend friend in callback.FriendList.Where(friend => friend.Relationship == EFriendRelationship.RequestRecipient)) {
|
foreach (SteamFriends.FriendsListCallback.Friend friend in callback.FriendList.Where(friend => friend.Relationship == EFriendRelationship.RequestRecipient)) {
|
||||||
if (IsMaster(friend.SteamID)) {
|
if (friend.SteamID.AccountType == EAccountType.Clan) {
|
||||||
SteamFriends.AddFriend(friend.SteamID);
|
if (IsMasterClanID(friend.SteamID)) {
|
||||||
} else if (BotConfig.IsBotAccount) {
|
ArchiHandler.AcceptClanInvite(friend.SteamID, true);
|
||||||
SteamFriends.RemoveFriend(friend.SteamID);
|
} else if (BotConfig.IsBotAccount) {
|
||||||
|
ArchiHandler.AcceptClanInvite(friend.SteamID, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (IsMaster(friend.SteamID)) {
|
||||||
|
SteamFriends.AddFriend(friend.SteamID);
|
||||||
|
} else if (BotConfig.IsBotAccount) {
|
||||||
|
SteamFriends.RemoveFriend(friend.SteamID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1103,7 +1175,7 @@ namespace ArchiSteamFarm {
|
|||||||
HashSet<uint> ownedPackageIDs = new HashSet<uint>(callback.LicenseList.Select(license => license.PackageID));
|
HashSet<uint> ownedPackageIDs = new HashSet<uint>(callback.LicenseList.Select(license => license.PackageID));
|
||||||
OwnedPackageIDs.ReplaceIfNeededWith(ownedPackageIDs);
|
OwnedPackageIDs.ReplaceIfNeededWith(ownedPackageIDs);
|
||||||
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false); // Wait a second for eventual PlayingSessionStateCallback
|
await Task.Delay(1000).ConfigureAwait(false); // Wait a second for eventual PlayingSessionStateCallback or SharedLibraryLockStatusCallback
|
||||||
|
|
||||||
if (!ArchiWebHandler.Ready) {
|
if (!ArchiWebHandler.Ready) {
|
||||||
for (byte i = 0; (i < Program.GlobalConfig.HttpTimeout) && !ArchiWebHandler.Ready; i++) {
|
for (byte i = 0; (i < Program.GlobalConfig.HttpTimeout) && !ArchiWebHandler.Ready; i++) {
|
||||||
@@ -1115,6 +1187,13 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normally we ResetGamesPlayed() in OnFarmingStopped() but there is no farming event if CardsFarmer module is disabled
|
||||||
|
// Therefore, trigger extra ResetGamesPlayed(), but only in this specific case
|
||||||
|
if (CardsFarmer.Paused) {
|
||||||
|
ResetGamesPlayed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We trigger OnNewGameAdded() anyway, as CardsFarmer has other things to handle regardless of being Paused or not
|
||||||
await CardsFarmer.OnNewGameAdded().ConfigureAwait(false);
|
await CardsFarmer.OnNewGameAdded().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1182,7 +1261,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sometimes Steam won't send us our own PersonaStateCallback, so request it explicitly
|
// Sometimes Steam won't send us our own PersonaStateCallback, so request it explicitly
|
||||||
SteamFriends.RequestFriendInfo(callback.ClientSteamID, EClientPersonaStateFlag.Presence);
|
SteamFriends.RequestFriendInfo(callback.ClientSteamID, EClientPersonaStateFlag.PlayerName | EClientPersonaStateFlag.Presence);
|
||||||
|
|
||||||
if (BotDatabase.MobileAuthenticator == null) {
|
if (BotDatabase.MobileAuthenticator == null) {
|
||||||
// Support and convert SDA files
|
// Support and convert SDA files
|
||||||
@@ -1279,7 +1358,17 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inform the steam servers that we're accepting this sentry file
|
// Inform the steam servers that we're accepting this sentry file
|
||||||
SteamUser.SendMachineAuthResponse(new SteamUser.MachineAuthDetails { JobID = callback.JobID, FileName = callback.FileName, BytesWritten = callback.BytesToWrite, FileSize = fileSize, Offset = callback.Offset, Result = EResult.OK, LastError = 0, OneTimePassword = callback.OneTimePassword, SentryFileHash = sentryHash });
|
SteamUser.SendMachineAuthResponse(new SteamUser.MachineAuthDetails {
|
||||||
|
JobID = callback.JobID,
|
||||||
|
FileName = callback.FileName,
|
||||||
|
BytesWritten = callback.BytesToWrite,
|
||||||
|
FileSize = fileSize,
|
||||||
|
Offset = callback.Offset,
|
||||||
|
Result = EResult.OK,
|
||||||
|
LastError = 0,
|
||||||
|
OneTimePassword = callback.OneTimePassword,
|
||||||
|
SentryFileHash = sentryHash
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNotifications(ArchiHandler.NotificationsCallback callback) {
|
private void OnNotifications(ArchiHandler.NotificationsCallback callback) {
|
||||||
@@ -1390,7 +1479,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ResetGamesPlayed() {
|
private void ResetGamesPlayed() {
|
||||||
if (PlayingBlocked) {
|
if (!IsPlayingPossible || (FamilySharingInactivityTimer != null)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1421,7 +1510,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> Response2FA(ulong steamID, string botName) {
|
private static async Task<string> Response2FA(ulong steamID, string botName) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1460,7 +1549,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> Response2FAConfirm(ulong steamID, string botName, bool confirm) {
|
private static async Task<string> Response2FAConfirm(ulong steamID, string botName, bool confirm) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1512,7 +1601,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> ResponseAddLicense(ulong steamID, string botName, string games) {
|
private static async Task<string> ResponseAddLicense(ulong steamID, string botName, string games) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(games)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(games)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName) + " || " + nameof(games));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName) + " || " + nameof(games));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1549,13 +1638,13 @@ namespace ArchiSteamFarm {
|
|||||||
return !IsOwner(steamID) ? null : GetAPIStatus();
|
return !IsOwner(steamID) ? null : GetAPIStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
Program.ArchiLogger.LogNullError(nameof(steamID));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ResponseExit(ulong steamID) {
|
private static string ResponseExit(ulong steamID) {
|
||||||
if (steamID == 0) {
|
if (steamID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
Program.ArchiLogger.LogNullError(nameof(steamID));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1593,7 +1682,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> ResponseFarm(ulong steamID, string botName) {
|
private static async Task<string> ResponseFarm(ulong steamID, string botName) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1632,6 +1721,10 @@ namespace ArchiSteamFarm {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!LootingAllowed) {
|
||||||
|
return "Looting is temporarily disabled!";
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsConnectedAndLoggedOn) {
|
if (!IsConnectedAndLoggedOn) {
|
||||||
return "This bot instance is not connected!";
|
return "This bot instance is not connected!";
|
||||||
}
|
}
|
||||||
@@ -1646,30 +1739,23 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
await Trading.LimitInventoryRequestsAsync().ConfigureAwait(false);
|
await Trading.LimitInventoryRequestsAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
HashSet<Steam.Item> inventory = await ArchiWebHandler.GetMySteamInventory(true).ConfigureAwait(false);
|
HashSet<Steam.Item> inventory = await ArchiWebHandler.GetMySteamInventory(true, BotConfig.LootableTypes).ConfigureAwait(false);
|
||||||
if ((inventory == null) || (inventory.Count == 0)) {
|
if ((inventory == null) || (inventory.Count == 0)) {
|
||||||
return "Nothing to send, inventory seems empty!";
|
return "Nothing to send, inventory seems empty!";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from our pending inventory all items that are not steam cards and boosters
|
|
||||||
if (inventory.RemoveWhere(item => (item.Type != Steam.Item.EType.TradingCard) && ((item.Type != Steam.Item.EType.FoilTradingCard) || !BotConfig.IsBotAccount) && (item.Type != Steam.Item.EType.BoosterPack)) > 0) {
|
|
||||||
if (inventory.Count == 0) {
|
|
||||||
return "Nothing to send, inventory seems empty!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!await ArchiWebHandler.SendTradeOffer(inventory, BotConfig.SteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) {
|
if (!await ArchiWebHandler.SendTradeOffer(inventory, BotConfig.SteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) {
|
||||||
return "Trade offer failed due to error!";
|
return "Trade offer failed due to error!";
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(1000).ConfigureAwait(false); // Sometimes we can be too fast for Steam servers to generate confirmations, wait a short moment
|
await Task.Delay(3000).ConfigureAwait(false); // Sometimes we can be too fast for Steam servers to generate confirmations, wait a short moment
|
||||||
await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, BotConfig.SteamMasterID).ConfigureAwait(false);
|
await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, BotConfig.SteamMasterID).ConfigureAwait(false);
|
||||||
return "Trade offer sent successfully!";
|
return "Trade offer sent successfully!";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string> ResponseLoot(ulong steamID, string botName) {
|
private static async Task<string> ResponseLoot(ulong steamID, string botName) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1687,7 +1773,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> ResponseLootAll(ulong steamID) {
|
private static async Task<string> ResponseLootAll(ulong steamID) {
|
||||||
if (steamID == 0) {
|
if (steamID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
Program.ArchiLogger.LogNullError(nameof(steamID));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1699,6 +1785,38 @@ namespace ArchiSteamFarm {
|
|||||||
return "Done!";
|
return "Done!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string ResponseLootSwitch(ulong steamID) {
|
||||||
|
if (steamID == 0) {
|
||||||
|
ArchiLogger.LogNullError(nameof(steamID));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsMaster(steamID)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LootingAllowed = !LootingAllowed;
|
||||||
|
return "Looting is now " + (LootingAllowed ? "enabled" : "disabled") + "!";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResponseLootSwitch(ulong steamID, string botName) {
|
||||||
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot bot;
|
||||||
|
if (Bots.TryGetValue(botName, out bot)) {
|
||||||
|
return bot.ResponseLootSwitch(steamID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsOwner(steamID)) {
|
||||||
|
return "Couldn't find any bot named " + botName + "!";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<string> ResponseOwns(ulong steamID, string query) {
|
private async Task<string> ResponseOwns(ulong steamID, string query) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(query)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(query)) {
|
||||||
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(query));
|
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(query));
|
||||||
@@ -1756,7 +1874,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> ResponseOwns(ulong steamID, string botName, string query) {
|
private static async Task<string> ResponseOwns(ulong steamID, string botName, string query) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(query)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(query)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName) + " || " + nameof(query));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName) + " || " + nameof(query));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1774,7 +1892,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> ResponseOwnsAll(ulong steamID, string query) {
|
private static async Task<string> ResponseOwnsAll(ulong steamID, string query) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(query)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(query)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(query));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(query));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1811,7 +1929,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string ResponsePassword(ulong steamID, string botName) {
|
private static string ResponsePassword(ulong steamID, string botName) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1857,7 +1975,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> ResponsePause(ulong steamID, string botName, bool sticky) {
|
private static async Task<string> ResponsePause(ulong steamID, string botName, bool sticky) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1897,7 +2015,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> ResponsePlay(ulong steamID, string botName, string games) {
|
private static async Task<string> ResponsePlay(ulong steamID, string botName, string games) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(games)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(games)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName) + " || " + nameof(games));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName) + " || " + nameof(games));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1944,8 +2062,8 @@ namespace ArchiSteamFarm {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool forward = !redeemFlags.HasFlag(ERedeemFlags.SkipForwarding) && (redeemFlags.HasFlag(ERedeemFlags.ForceForwarding) || BotConfig.ForwardKeysToOtherBots);
|
bool forward = !redeemFlags.HasFlag(ERedeemFlags.SkipForwarding) && (redeemFlags.HasFlag(ERedeemFlags.ForceForwarding) || BotConfig.RedeemingPreferences.HasFlag(BotConfig.ERedeemingPreferences.Forwarding));
|
||||||
bool distribute = !redeemFlags.HasFlag(ERedeemFlags.SkipDistribution) && (redeemFlags.HasFlag(ERedeemFlags.ForceDistribution) || BotConfig.DistributeKeys);
|
bool distribute = !redeemFlags.HasFlag(ERedeemFlags.SkipDistribution) && (redeemFlags.HasFlag(ERedeemFlags.ForceDistribution) || BotConfig.RedeemingPreferences.HasFlag(BotConfig.ERedeemingPreferences.Distributing));
|
||||||
message = message.Replace(",", Environment.NewLine);
|
message = message.Replace(",", Environment.NewLine);
|
||||||
|
|
||||||
StringBuilder response = new StringBuilder();
|
StringBuilder response = new StringBuilder();
|
||||||
@@ -2060,7 +2178,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> ResponseRedeem(ulong steamID, string botName, string message, ERedeemFlags redeemFlags = ERedeemFlags.None) {
|
private static async Task<string> ResponseRedeem(ulong steamID, string botName, string message, ERedeemFlags redeemFlags = ERedeemFlags.None) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(message)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName) || string.IsNullOrEmpty(message)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName) + " || " + nameof(message));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName) + " || " + nameof(message));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2078,7 +2196,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string ResponseRejoinChat(ulong steamID) {
|
private static string ResponseRejoinChat(ulong steamID) {
|
||||||
if (steamID == 0) {
|
if (steamID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
Program.ArchiLogger.LogNullError(nameof(steamID));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2095,7 +2213,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string ResponseRestart(ulong steamID) {
|
private static string ResponseRestart(ulong steamID) {
|
||||||
if (steamID == 0) {
|
if (steamID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
Program.ArchiLogger.LogNullError(nameof(steamID));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2137,7 +2255,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string ResponseResume(ulong steamID, string botName) {
|
private static string ResponseResume(ulong steamID, string botName) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2174,7 +2292,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string ResponseStart(ulong steamID, string botName) {
|
private static string ResponseStart(ulong steamID, string botName) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2192,7 +2310,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string ResponseStartAll(ulong steamID) {
|
private static string ResponseStartAll(ulong steamID) {
|
||||||
if (steamID == 0) {
|
if (steamID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
Program.ArchiLogger.LogNullError(nameof(steamID));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2233,6 +2351,10 @@ namespace ArchiSteamFarm {
|
|||||||
return "Bot " + BotName + " is paused or running in manual mode.";
|
return "Bot " + BotName + " is paused or running in manual mode.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsLimitedUser) {
|
||||||
|
return "Bot " + BotName + " is limited.";
|
||||||
|
}
|
||||||
|
|
||||||
if (CardsFarmer.CurrentGamesFarming.Count == 0) {
|
if (CardsFarmer.CurrentGamesFarming.Count == 0) {
|
||||||
return "Bot " + BotName + " is not farming anything.";
|
return "Bot " + BotName + " is not farming anything.";
|
||||||
}
|
}
|
||||||
@@ -2252,7 +2374,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string ResponseStatus(ulong steamID, string botName) {
|
private static string ResponseStatus(ulong steamID, string botName) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2270,7 +2392,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string ResponseStatusAll(ulong steamID) {
|
private static string ResponseStatusAll(ulong steamID) {
|
||||||
if (steamID == 0) {
|
if (steamID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
Program.ArchiLogger.LogNullError(nameof(steamID));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2304,7 +2426,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string ResponseStop(ulong steamID, string botName) {
|
private static string ResponseStop(ulong steamID, string botName) {
|
||||||
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
if ((steamID == 0) || string.IsNullOrEmpty(botName)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
Program.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2331,7 +2453,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static async Task<string> ResponseUpdate(ulong steamID) {
|
private static async Task<string> ResponseUpdate(ulong steamID) {
|
||||||
if (steamID == 0) {
|
if (steamID == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(steamID));
|
Program.ArchiLogger.LogNullError(nameof(steamID));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2416,7 +2538,10 @@ namespace ArchiSteamFarm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FamilySharingInactivityTimer = new Timer(e => CheckFamilySharingInactivity(), null, TimeSpan.FromMinutes(FamilySharingInactivityMinutes), // Delay
|
FamilySharingInactivityTimer = new Timer(
|
||||||
|
e => CheckFamilySharingInactivity(),
|
||||||
|
null,
|
||||||
|
TimeSpan.FromMinutes(FamilySharingInactivityMinutes), // Delay
|
||||||
Timeout.InfiniteTimeSpan // Period
|
Timeout.InfiniteTimeSpan // Period
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2426,7 +2551,6 @@ namespace ArchiSteamFarm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FamilySharingInactivityTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
|
||||||
FamilySharingInactivityTimer.Dispose();
|
FamilySharingInactivityTimer.Dispose();
|
||||||
FamilySharingInactivityTimer = null;
|
FamilySharingInactivityTimer = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using ArchiSteamFarm.JSON;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace ArchiSteamFarm {
|
namespace ArchiSteamFarm {
|
||||||
@@ -53,9 +54,6 @@ namespace ArchiSteamFarm {
|
|||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly bool DismissInventoryNotifications = true;
|
internal readonly bool DismissInventoryNotifications = true;
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
|
||||||
internal readonly bool DistributeKeys = false;
|
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly bool Enabled = false;
|
internal readonly bool Enabled = false;
|
||||||
|
|
||||||
@@ -65,9 +63,6 @@ namespace ArchiSteamFarm {
|
|||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly bool FarmOffline = false;
|
internal readonly bool FarmOffline = false;
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
|
||||||
internal readonly bool ForwardKeysToOtherBots = false;
|
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly HashSet<uint> GamesPlayedWhileIdle = new HashSet<uint>();
|
internal readonly HashSet<uint> GamesPlayedWhileIdle = new HashSet<uint>();
|
||||||
|
|
||||||
@@ -77,12 +72,18 @@ namespace ArchiSteamFarm {
|
|||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly bool IsBotAccount = false;
|
internal readonly bool IsBotAccount = false;
|
||||||
|
|
||||||
|
[JsonProperty(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)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly CryptoHelper.ECryptoMethod PasswordFormat = CryptoHelper.ECryptoMethod.PlainText;
|
internal readonly CryptoHelper.ECryptoMethod PasswordFormat = CryptoHelper.ECryptoMethod.PlainText;
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly bool Paused = false;
|
internal readonly bool Paused = false;
|
||||||
|
|
||||||
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
|
internal readonly ERedeemingPreferences RedeemingPreferences = ERedeemingPreferences.None;
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly bool SendOnFarmingFinished = false;
|
internal readonly bool SendOnFarmingFinished = false;
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
internal static BotConfig Load(string filePath) {
|
internal static BotConfig Load(string filePath) {
|
||||||
if (string.IsNullOrEmpty(filePath)) {
|
if (string.IsNullOrEmpty(filePath)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(filePath));
|
Program.ArchiLogger.LogNullError(nameof(filePath));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,12 +135,12 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
botConfig = JsonConvert.DeserializeObject<BotConfig>(File.ReadAllText(filePath));
|
botConfig = JsonConvert.DeserializeObject<BotConfig>(File.ReadAllText(filePath));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (botConfig == null) {
|
if (botConfig == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(botConfig));
|
Program.ArchiLogger.LogNullError(nameof(botConfig));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +156,7 @@ namespace ArchiSteamFarm {
|
|||||||
return botConfig;
|
return botConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.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 " + CardsFarmer.MaxGamesPlayedConcurrently + " games concurrently is not possible, only first " + CardsFarmer.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(CardsFarmer.MaxGamesPlayedConcurrently));
|
||||||
botConfig.GamesPlayedWhileIdle.IntersectWith(validGames);
|
botConfig.GamesPlayedWhileIdle.IntersectWith(validGames);
|
||||||
@@ -176,6 +177,14 @@ namespace ArchiSteamFarm {
|
|||||||
NamesDescending
|
NamesDescending
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum ERedeemingPreferences : byte {
|
||||||
|
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||||
|
None = 0,
|
||||||
|
Forwarding = 1,
|
||||||
|
Distributing = 2
|
||||||
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
internal enum ETradingPreferences : byte {
|
internal enum ETradingPreferences : byte {
|
||||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
internal static BotDatabase Load(string filePath) {
|
internal static BotDatabase Load(string filePath) {
|
||||||
if (string.IsNullOrEmpty(filePath)) {
|
if (string.IsNullOrEmpty(filePath)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(filePath));
|
Program.ArchiLogger.LogNullError(nameof(filePath));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,12 +95,12 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
botDatabase = JsonConvert.DeserializeObject<BotDatabase>(File.ReadAllText(filePath));
|
botDatabase = JsonConvert.DeserializeObject<BotDatabase>(File.ReadAllText(filePath));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (botDatabase == null) {
|
if (botDatabase == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(botDatabase));
|
Program.ArchiLogger.LogNullError(nameof(botDatabase));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ namespace ArchiSteamFarm {
|
|||||||
internal void Save() {
|
internal void Save() {
|
||||||
string json = JsonConvert.SerializeObject(this);
|
string json = JsonConvert.SerializeObject(this);
|
||||||
if (string.IsNullOrEmpty(json)) {
|
if (string.IsNullOrEmpty(json)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(json));
|
Program.ArchiLogger.LogNullError(nameof(json));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ namespace ArchiSteamFarm {
|
|||||||
File.WriteAllText(FilePath, json);
|
File.WriteAllText(FilePath, json);
|
||||||
break;
|
break;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
|
|||||||
58
ArchiSteamFarm/CMsgs/CMsgClientClanInviteAction.cs
Normal file
58
ArchiSteamFarm/CMsgs/CMsgClientClanInviteAction.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
_ _ _ ____ _ _____
|
||||||
|
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||||
|
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||||
|
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||||
|
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||||
|
|
||||||
|
Copyright 2015-2016 Łukasz "JustArchi" Domeradzki
|
||||||
|
Contact: JustArchi@JustArchi.net
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using SteamKit2;
|
||||||
|
using SteamKit2.Internal;
|
||||||
|
|
||||||
|
namespace ArchiSteamFarm.CMsgs {
|
||||||
|
internal sealed class CMsgClientClanInviteAction : ISteamSerializableMessage {
|
||||||
|
internal bool AcceptInvite { private get; set; }
|
||||||
|
internal ulong ClanID { private get; set; }
|
||||||
|
|
||||||
|
void ISteamSerializable.Deserialize(Stream stream) {
|
||||||
|
if (stream == null) {
|
||||||
|
Program.ArchiLogger.LogNullError(nameof(stream));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryReader binaryReader = new BinaryReader(stream);
|
||||||
|
ClanID = binaryReader.ReadUInt64();
|
||||||
|
AcceptInvite = binaryReader.ReadBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
EMsg ISteamSerializableMessage.GetEMsg() => EMsg.ClientAcknowledgeClanInvite;
|
||||||
|
|
||||||
|
void ISteamSerializable.Serialize(Stream stream) {
|
||||||
|
if (stream == null) {
|
||||||
|
Program.ArchiLogger.LogNullError(nameof(stream));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryWriter binaryWriter = new BinaryWriter(stream);
|
||||||
|
binaryWriter.Write(ClanID);
|
||||||
|
binaryWriter.Write(AcceptInvite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,8 @@ namespace ArchiSteamFarm {
|
|||||||
internal sealed class CardsFarmer : IDisposable {
|
internal sealed class CardsFarmer : IDisposable {
|
||||||
internal const byte MaxGamesPlayedConcurrently = 32; // This is limit introduced by Steam Network
|
internal const byte MaxGamesPlayedConcurrently = 32; // This is limit introduced by Steam Network
|
||||||
|
|
||||||
|
private static readonly HashSet<uint> UntrustedAppIDs = new HashSet<uint> { 440, 570, 730 };
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
internal readonly ConcurrentHashSet<Game> CurrentGamesFarming = new ConcurrentHashSet<Game>();
|
internal readonly ConcurrentHashSet<Game> CurrentGamesFarming = new ConcurrentHashSet<Game>();
|
||||||
|
|
||||||
@@ -62,7 +64,10 @@ namespace ArchiSteamFarm {
|
|||||||
Bot = bot;
|
Bot = bot;
|
||||||
|
|
||||||
if (Program.GlobalConfig.IdleFarmingPeriod > 0) {
|
if (Program.GlobalConfig.IdleFarmingPeriod > 0) {
|
||||||
IdleFarmingTimer = new Timer(e => CheckGamesForFarming(), null, TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) + TimeSpan.FromMinutes(0.5 * Bot.Bots.Count), // Delay
|
IdleFarmingTimer = new Timer(
|
||||||
|
e => CheckGamesForFarming(),
|
||||||
|
null,
|
||||||
|
TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) + TimeSpan.FromMinutes(0.5 * Bot.Bots.Count), // Delay
|
||||||
TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) // Period
|
TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) // Period
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -82,15 +87,16 @@ namespace ArchiSteamFarm {
|
|||||||
internal void OnDisconnected() => StopFarming().Forget();
|
internal void OnDisconnected() => StopFarming().Forget();
|
||||||
|
|
||||||
internal async Task OnNewGameAdded() {
|
internal async Task OnNewGameAdded() {
|
||||||
|
// If we're not farming yet, obviously it's worth it to make a check
|
||||||
if (!NowFarming) {
|
if (!NowFarming) {
|
||||||
// If we're not farming yet, obviously it's worth it to make a check
|
|
||||||
StartFarming().Forget();
|
StartFarming().Forget();
|
||||||
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
|
||||||
|
// 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)) {
|
if (Bot.BotConfig.CardDropsRestricted && (GamesToFarm.Count > 0) && (GamesToFarm.Min(game => game.HoursPlayed) < 2)) {
|
||||||
// If we have Complex algorithm and some games to boost, it's also worth to make a check
|
|
||||||
// That's because we would check for new games after our current round anyway
|
|
||||||
await StopFarming().ConfigureAwait(false);
|
await StopFarming().ConfigureAwait(false);
|
||||||
StartFarming().Forget();
|
StartFarming().Forget();
|
||||||
}
|
}
|
||||||
@@ -251,6 +257,25 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CheckGame(uint appID, string name, float hours) {
|
||||||
|
if ((appID == 0) || string.IsNullOrEmpty(name) || (hours < 0)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(name) + " || " + nameof(hours));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ushort? cardsRemaining = await GetCardsRemaining(appID).ConfigureAwait(false);
|
||||||
|
if (!cardsRemaining.HasValue) {
|
||||||
|
Bot.ArchiLogger.LogGenericWarning("Could not check cards status for " + appID + " (" + name + "), will try again later!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardsRemaining.Value == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GamesToFarm.Add(new Game(appID, name, hours, cardsRemaining.Value));
|
||||||
|
}
|
||||||
|
|
||||||
private void CheckGamesForFarming() {
|
private void CheckGamesForFarming() {
|
||||||
if (NowFarming || Paused || !Bot.IsConnectedAndLoggedOn) {
|
if (NowFarming || Paused || !Bot.IsConnectedAndLoggedOn) {
|
||||||
return;
|
return;
|
||||||
@@ -259,118 +284,167 @@ namespace ArchiSteamFarm {
|
|||||||
StartFarming().Forget();
|
StartFarming().Forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckPage(HtmlDocument htmlDocument) {
|
private async Task CheckPage(HtmlDocument htmlDocument) {
|
||||||
if (htmlDocument == null) {
|
if (htmlDocument == null) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(htmlDocument));
|
Bot.ArchiLogger.LogNullError(nameof(htmlDocument));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HtmlNodeCollection htmlNodes = htmlDocument.DocumentNode.SelectNodes("//div[@class='badge_title_stats']");
|
HtmlNodeCollection htmlNodes = htmlDocument.DocumentNode.SelectNodes("//div[@class='badge_title_stats_content']");
|
||||||
if (htmlNodes == null) { // No eligible badges
|
if (htmlNodes == null) {
|
||||||
|
// No eligible badges whatsoever
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashSet<Task> extraTasks = new HashSet<Task>();
|
||||||
|
|
||||||
foreach (HtmlNode htmlNode in htmlNodes) {
|
foreach (HtmlNode htmlNode in htmlNodes) {
|
||||||
HtmlNode farmingNode = htmlNode.SelectSingleNode(".//a[@class='btn_green_white_innerfade btn_small_thin']");
|
HtmlNode appIDNode = htmlNode.SelectSingleNode(".//div[@class='card_drop_info_dialog']");
|
||||||
if (farmingNode == null) {
|
if (appIDNode == null) {
|
||||||
continue; // This game is not needed for farming
|
// It's just a badge, nothing more
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
HtmlNode progressNode = htmlNode.SelectSingleNode(".//span[@class='progress_info_bold']");
|
string appIDString = appIDNode.GetAttributeValue("id", null);
|
||||||
if (progressNode == null) {
|
if (string.IsNullOrEmpty(appIDString)) {
|
||||||
continue; // e.g. Holiday Sale 2015
|
Bot.ArchiLogger.LogNullError(nameof(appIDString));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppIDs
|
string[] appIDSplitted = appIDString.Split('_');
|
||||||
string steamLink = farmingNode.GetAttributeValue("href", null);
|
if (appIDSplitted.Length < 5) {
|
||||||
if (string.IsNullOrEmpty(steamLink)) {
|
Bot.ArchiLogger.LogNullError(nameof(appIDSplitted));
|
||||||
Bot.ArchiLogger.LogNullError(nameof(steamLink));
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = steamLink.LastIndexOf('/');
|
appIDString = appIDSplitted[4];
|
||||||
if (index < 0) {
|
|
||||||
Bot.ArchiLogger.LogNullError(nameof(index));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
|
||||||
if (steamLink.Length <= index) {
|
|
||||||
Bot.ArchiLogger.LogNullError(nameof(steamLink.Length));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
steamLink = steamLink.Substring(index);
|
|
||||||
|
|
||||||
uint appID;
|
uint appID;
|
||||||
if (!uint.TryParse(steamLink, out appID) || (appID == 0)) {
|
if (!uint.TryParse(appIDString, out appID) || (appID == 0)) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(appID));
|
Bot.ArchiLogger.LogNullError(nameof(appID));
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GlobalConfig.GlobalBlacklist.Contains(appID) || Program.GlobalConfig.Blacklist.Contains(appID)) {
|
if (GlobalConfig.GlobalBlacklist.Contains(appID) || Program.GlobalConfig.Blacklist.Contains(appID)) {
|
||||||
|
// We have this appID blacklisted, so skip it
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cards
|
||||||
|
HtmlNode progressNode = htmlNode.SelectSingleNode(".//span[@class='progress_info_bold']");
|
||||||
|
if (progressNode == null) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(progressNode));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string progressText = progressNode.InnerText;
|
||||||
|
if (string.IsNullOrEmpty(progressText)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(progressText));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ushort cardsRemaining = 0;
|
||||||
|
Match progressMatch = Regex.Match(progressText, @"\d+");
|
||||||
|
|
||||||
|
// This might fail if we have no card drops remaining, that's fine
|
||||||
|
if (progressMatch.Success) {
|
||||||
|
if (!ushort.TryParse(progressMatch.Value, out cardsRemaining)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(cardsRemaining));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardsRemaining == 0) {
|
||||||
|
// Normally we'd trust this information and simply skip the rest
|
||||||
|
// However, Steam is so fucked up that we can't simply assume that it's correct
|
||||||
|
// It's entirely possible that actual game page has different info, and badge page lied to us
|
||||||
|
// We can't check every single game though, as this will literally kill people with cards from games they don't own
|
||||||
|
if (!UntrustedAppIDs.Contains(appID)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// To save us on extra work, check cards earned so far first
|
||||||
|
HtmlNode cardsEarnedNode = htmlNode.SelectSingleNode(".//div[@class='card_drop_info_header']");
|
||||||
|
string cardsEarnedText = cardsEarnedNode.InnerText;
|
||||||
|
if (string.IsNullOrEmpty(cardsEarnedText)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(cardsEarnedText));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Match cardsEarnedMatch = Regex.Match(cardsEarnedText, @"\d+");
|
||||||
|
if (!cardsEarnedMatch.Success) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(cardsEarnedMatch));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ushort cardsEarned;
|
||||||
|
if (!ushort.TryParse(cardsEarnedMatch.Value, out cardsEarned)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(cardsEarned));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardsEarned > 0) {
|
||||||
|
// If we already earned some cards for this game, it's very likely that it's done
|
||||||
|
// Let's hope that trusting cardsRemaining AND cardsEarned is enough
|
||||||
|
// If I ever hear that it's not, I'll most likely need a doctor
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have no cardsRemaining and no cardsEarned, it's either:
|
||||||
|
// - A game we don't own physically, but we have cards from it in inventory
|
||||||
|
// - F2P game that we didn't spend any money in, but we have cards from it in inventory
|
||||||
|
// - Steam fuckup
|
||||||
|
// As you can guess, we must follow the rest of the logic in case of Steam fuckup
|
||||||
|
// Please kill me ;_;
|
||||||
|
}
|
||||||
|
|
||||||
// Hours
|
// Hours
|
||||||
HtmlNode timeNode = htmlNode.SelectSingleNode(".//div[@class='badge_title_stats_playtime']");
|
HtmlNode timeNode = htmlNode.SelectSingleNode(".//div[@class='badge_title_stats_playtime']");
|
||||||
if (timeNode == null) {
|
if (timeNode == null) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(timeNode));
|
Bot.ArchiLogger.LogNullError(nameof(timeNode));
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string hoursString = timeNode.InnerText;
|
string hoursString = timeNode.InnerText;
|
||||||
if (string.IsNullOrEmpty(hoursString)) {
|
if (string.IsNullOrEmpty(hoursString)) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(hoursString));
|
Bot.ArchiLogger.LogNullError(nameof(hoursString));
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float hours = 0;
|
float hours = 0;
|
||||||
|
|
||||||
Match hoursMatch = Regex.Match(hoursString, @"[0-9\.,]+");
|
Match hoursMatch = Regex.Match(hoursString, @"[0-9\.,]+");
|
||||||
if (hoursMatch.Success) { // Might fail if we have 0.0 hours played
|
|
||||||
|
// This might fail if we have exactly 0.0 hours played, that's fine
|
||||||
|
if (hoursMatch.Success) {
|
||||||
if (!float.TryParse(hoursMatch.Value, NumberStyles.Number, CultureInfo.InvariantCulture, out hours)) {
|
if (!float.TryParse(hoursMatch.Value, NumberStyles.Number, CultureInfo.InvariantCulture, out hours)) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(hours));
|
Bot.ArchiLogger.LogNullError(nameof(hours));
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cards
|
|
||||||
string progress = progressNode.InnerText;
|
|
||||||
if (string.IsNullOrEmpty(progress)) {
|
|
||||||
Bot.ArchiLogger.LogNullError(nameof(progress));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Match progressMatch = Regex.Match(progress, @"\d+");
|
|
||||||
if (!progressMatch.Success) {
|
|
||||||
Bot.ArchiLogger.LogNullError(nameof(progressMatch));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ushort cardsRemaining;
|
|
||||||
if (!ushort.TryParse(progressMatch.Value, out cardsRemaining) || (cardsRemaining == 0)) {
|
|
||||||
Bot.ArchiLogger.LogNullError(nameof(cardsRemaining));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Names
|
// Names
|
||||||
HtmlNode nameNode = htmlNode.SelectSingleNode("(.//div[@class='card_drop_info_body'])[last()]");
|
HtmlNode nameNode = htmlNode.SelectSingleNode("(.//div[@class='card_drop_info_body'])[last()]");
|
||||||
if (nameNode == null) {
|
if (nameNode == null) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(nameNode));
|
Bot.ArchiLogger.LogNullError(nameof(nameNode));
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string name = nameNode.InnerText;
|
string name = nameNode.InnerText;
|
||||||
if (string.IsNullOrEmpty(name)) {
|
if (string.IsNullOrEmpty(name)) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(name));
|
Bot.ArchiLogger.LogNullError(nameof(name));
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We handle two cases here - normal one, and no card drops remaining
|
||||||
int nameStartIndex = name.IndexOf(" by playing ", StringComparison.Ordinal);
|
int nameStartIndex = name.IndexOf(" by playing ", StringComparison.Ordinal);
|
||||||
if (nameStartIndex <= 0) {
|
if (nameStartIndex <= 0) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(nameStartIndex));
|
nameStartIndex = name.IndexOf("You don't have any more drops remaining for ", StringComparison.Ordinal);
|
||||||
return;
|
if (nameStartIndex <= 0) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(nameStartIndex));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nameStartIndex += 32; // + 12 below
|
||||||
}
|
}
|
||||||
|
|
||||||
nameStartIndex += 12;
|
nameStartIndex += 12;
|
||||||
@@ -378,14 +452,24 @@ namespace ArchiSteamFarm {
|
|||||||
int nameEndIndex = name.LastIndexOf('.');
|
int nameEndIndex = name.LastIndexOf('.');
|
||||||
if (nameEndIndex <= nameStartIndex) {
|
if (nameEndIndex <= nameStartIndex) {
|
||||||
Bot.ArchiLogger.LogNullError(nameof(nameEndIndex));
|
Bot.ArchiLogger.LogNullError(nameof(nameEndIndex));
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = name.Substring(nameStartIndex, nameEndIndex - nameStartIndex);
|
name = name.Substring(nameStartIndex, nameEndIndex - nameStartIndex);
|
||||||
|
|
||||||
// Final result
|
// We have two possible cases here
|
||||||
GamesToFarm.Add(new Game(appID, name, hours, cardsRemaining));
|
// Either we have decent info about appID, name, hours and cardsRemaining (cardsRemaining > 0)
|
||||||
|
// OR we strongly believe that Steam lied to us, in this case we will need to check game invidually (cardsRemaining == 0)
|
||||||
|
|
||||||
|
if (cardsRemaining > 0) {
|
||||||
|
GamesToFarm.Add(new Game(appID, name, hours, cardsRemaining));
|
||||||
|
} else {
|
||||||
|
extraTasks.Add(CheckGame(appID, name, hours));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have any pending tasks, wait for them
|
||||||
|
await Task.WhenAll(extraTasks).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CheckPage(byte page) {
|
private async Task CheckPage(byte page) {
|
||||||
@@ -399,7 +483,7 @@ namespace ArchiSteamFarm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckPage(htmlDocument);
|
await CheckPage(htmlDocument).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> Farm(Game game) {
|
private async Task<bool> Farm(Game game) {
|
||||||
@@ -522,6 +606,39 @@ namespace ArchiSteamFarm {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<ushort?> GetCardsRemaining(uint appID) {
|
||||||
|
if (appID == 0) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(appID));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetGameCardsPage(appID).ConfigureAwait(false);
|
||||||
|
|
||||||
|
HtmlNode progressNode = htmlDocument?.DocumentNode.SelectSingleNode("//span[@class='progress_info_bold']");
|
||||||
|
if (progressNode == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string progress = progressNode.InnerText;
|
||||||
|
if (string.IsNullOrEmpty(progress)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(progress));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Match match = Regex.Match(progress, @"\d+");
|
||||||
|
if (!match.Success) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ushort cardsRemaining;
|
||||||
|
if (ushort.TryParse(match.Value, out cardsRemaining) && (cardsRemaining != 0)) {
|
||||||
|
return cardsRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(cardsRemaining));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<bool> IsAnythingToFarm() {
|
private async Task<bool> IsAnythingToFarm() {
|
||||||
Bot.ArchiLogger.LogGenericInfo("Checking badges...");
|
Bot.ArchiLogger.LogGenericInfo("Checking badges...");
|
||||||
|
|
||||||
@@ -550,19 +667,16 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GamesToFarm.ClearAndTrim();
|
GamesToFarm.ClearAndTrim();
|
||||||
CheckPage(htmlDocument);
|
|
||||||
|
|
||||||
if (maxPages == 1) {
|
List<Task> tasks = new List<Task>(maxPages - 1) { CheckPage(htmlDocument) };
|
||||||
SortGamesToFarm();
|
|
||||||
return GamesToFarm.Count > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Bot.ArchiLogger.LogGenericInfo("Checking other pages...");
|
if (maxPages > 1) {
|
||||||
|
Bot.ArchiLogger.LogGenericInfo("Checking other pages...");
|
||||||
|
|
||||||
List<Task> tasks = new List<Task>(maxPages - 1);
|
for (byte page = 2; page <= maxPages; page++) {
|
||||||
for (byte page = 2; page <= maxPages; page++) {
|
byte currentPage = page; // We need a copy of variable being passed when in for loops, as loop will proceed before task is launched
|
||||||
byte currentPage = page; // We need a copy of variable being passed when in for loops, as loop will proceed before task is launched
|
tasks.Add(CheckPage(currentPage));
|
||||||
tasks.Add(CheckPage(currentPage));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||||
@@ -576,37 +690,16 @@ namespace ArchiSteamFarm {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetGameCardsPage(game.AppID).ConfigureAwait(false);
|
ushort? cardsRemaining = await GetCardsRemaining(game.AppID).ConfigureAwait(false);
|
||||||
if (htmlDocument == null) {
|
if (!cardsRemaining.HasValue) {
|
||||||
|
Bot.ArchiLogger.LogGenericWarning("Could not check cards status for " + game.AppID + " (" + game.GameName + "), will try again later!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//span[@class='progress_info_bold']");
|
game.CardsRemaining = cardsRemaining.Value;
|
||||||
if (htmlNode == null) {
|
|
||||||
Bot.ArchiLogger.LogNullError(nameof(htmlNode));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string progress = htmlNode.InnerText;
|
Bot.ArchiLogger.LogGenericInfo("Status for " + game.AppID + " (" + game.GameName + "): " + game.CardsRemaining + " cards remaining");
|
||||||
if (string.IsNullOrEmpty(progress)) {
|
return game.CardsRemaining > 0;
|
||||||
Bot.ArchiLogger.LogNullError(nameof(progress));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ushort cardsRemaining = 0;
|
|
||||||
|
|
||||||
Match match = Regex.Match(progress, @"\d+");
|
|
||||||
if (match.Success) {
|
|
||||||
if (!ushort.TryParse(match.Value, out cardsRemaining)) {
|
|
||||||
Bot.ArchiLogger.LogNullError(nameof(cardsRemaining));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
game.CardsRemaining = cardsRemaining;
|
|
||||||
|
|
||||||
Bot.ArchiLogger.LogGenericInfo("Status for " + game.AppID + " (" + game.GameName + "): " + cardsRemaining + " cards remaining");
|
|
||||||
return cardsRemaining > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SortGamesToFarm() {
|
private void SortGamesToFarm() {
|
||||||
@@ -673,11 +766,11 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj) {
|
public override bool Equals(object obj) {
|
||||||
if (ReferenceEquals(null, obj)) {
|
if (obj == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReferenceEquals(this, obj)) {
|
if (obj == this) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
internal static string Decrypt(ECryptoMethod cryptoMethod, string encrypted) {
|
internal static string Decrypt(ECryptoMethod cryptoMethod, string encrypted) {
|
||||||
if (string.IsNullOrEmpty(encrypted)) {
|
if (string.IsNullOrEmpty(encrypted)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(encrypted));
|
Program.ArchiLogger.LogNullError(nameof(encrypted));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
internal static string Encrypt(ECryptoMethod cryptoMethod, string decrypted) {
|
internal static string Encrypt(ECryptoMethod cryptoMethod, string decrypted) {
|
||||||
if (string.IsNullOrEmpty(decrypted)) {
|
if (string.IsNullOrEmpty(decrypted)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(decrypted));
|
Program.ArchiLogger.LogNullError(nameof(decrypted));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
internal static void SetEncryptionKey(string key) {
|
internal static void SetEncryptionKey(string key) {
|
||||||
if (string.IsNullOrEmpty(key)) {
|
if (string.IsNullOrEmpty(key)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(key));
|
Program.ArchiLogger.LogNullError(nameof(key));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static string DecryptAES(string encrypted) {
|
private static string DecryptAES(string encrypted) {
|
||||||
if (string.IsNullOrEmpty(encrypted)) {
|
if (string.IsNullOrEmpty(encrypted)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(encrypted));
|
Program.ArchiLogger.LogNullError(nameof(encrypted));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,14 +91,14 @@ namespace ArchiSteamFarm {
|
|||||||
decryptedData = SteamKit2.CryptoHelper.SymmetricDecrypt(decryptedData, key);
|
decryptedData = SteamKit2.CryptoHelper.SymmetricDecrypt(decryptedData, key);
|
||||||
return Encoding.UTF8.GetString(decryptedData);
|
return Encoding.UTF8.GetString(decryptedData);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string DecryptProtectedDataForCurrentUser(string encrypted) {
|
private static string DecryptProtectedDataForCurrentUser(string encrypted) {
|
||||||
if (string.IsNullOrEmpty(encrypted)) {
|
if (string.IsNullOrEmpty(encrypted)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(encrypted));
|
Program.ArchiLogger.LogNullError(nameof(encrypted));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,14 +108,14 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
return Encoding.UTF8.GetString(decryptedData);
|
return Encoding.UTF8.GetString(decryptedData);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string EncryptAES(string decrypted) {
|
private static string EncryptAES(string decrypted) {
|
||||||
if (string.IsNullOrEmpty(decrypted)) {
|
if (string.IsNullOrEmpty(decrypted)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(decrypted));
|
Program.ArchiLogger.LogNullError(nameof(decrypted));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,14 +129,14 @@ namespace ArchiSteamFarm {
|
|||||||
encryptedData = SteamKit2.CryptoHelper.SymmetricEncrypt(encryptedData, key);
|
encryptedData = SteamKit2.CryptoHelper.SymmetricEncrypt(encryptedData, key);
|
||||||
return Convert.ToBase64String(encryptedData);
|
return Convert.ToBase64String(encryptedData);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string EncryptProtectedDataForCurrentUser(string decrypted) {
|
private static string EncryptProtectedDataForCurrentUser(string decrypted) {
|
||||||
if (string.IsNullOrEmpty(decrypted)) {
|
if (string.IsNullOrEmpty(decrypted)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(decrypted));
|
Program.ArchiLogger.LogNullError(nameof(decrypted));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
return Convert.ToBase64String(encryptedData);
|
return Convert.ToBase64String(encryptedData);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ namespace ArchiSteamFarm {
|
|||||||
internal sealed class DebugListener : IDebugListener {
|
internal sealed class DebugListener : IDebugListener {
|
||||||
public void WriteLine(string category, string msg) {
|
public void WriteLine(string category, string msg) {
|
||||||
if (string.IsNullOrEmpty(category) && string.IsNullOrEmpty(msg)) {
|
if (string.IsNullOrEmpty(category) && string.IsNullOrEmpty(msg)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(category) + " && " + nameof(msg));
|
Program.ArchiLogger.LogNullError(nameof(category) + " && " + nameof(msg));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogGenericDebug(category + " | " + msg);
|
Program.ArchiLogger.LogGenericDebug(category + " | " + msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace ArchiSteamFarm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogGenericInfo("No bots are running, exiting");
|
Program.ArchiLogger.LogGenericInfo("No bots are running, exiting");
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
Program.Shutdown();
|
Program.Shutdown();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
<Weavers>
|
<Weavers>
|
||||||
<Costura IncludeDebugSymbols='false' />
|
<Costura IncludeDebugSymbols='false' />
|
||||||
</Weavers>
|
</Weavers>
|
||||||
@@ -42,7 +42,7 @@ namespace ArchiSteamFarm {
|
|||||||
private const ushort DefaultWCFPort = 1242;
|
private const ushort DefaultWCFPort = 1242;
|
||||||
|
|
||||||
// This is hardcoded blacklist which should not be possible to change
|
// 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 };
|
internal static readonly HashSet<uint> GlobalBlacklist = new HashSet<uint> { 267420, 303700, 335590, 368020, 425280, 480730, 566020 };
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly bool AutoRestart = true;
|
internal readonly bool AutoRestart = true;
|
||||||
@@ -59,9 +59,6 @@ namespace ArchiSteamFarm {
|
|||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly byte FarmingDelay = DefaultFarmingDelay;
|
internal readonly byte FarmingDelay = DefaultFarmingDelay;
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
|
||||||
internal readonly bool ForceHttp = false;
|
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly byte GiftsLimiterDelay = 1;
|
internal readonly byte GiftsLimiterDelay = 1;
|
||||||
|
|
||||||
@@ -102,14 +99,14 @@ namespace ArchiSteamFarm {
|
|||||||
internal readonly ushort WCFPort = DefaultWCFPort;
|
internal readonly ushort WCFPort = DefaultWCFPort;
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
internal string WCFHostname { get; set; } = "localhost";
|
internal string WCFHost { get; set; } = "127.0.0.1";
|
||||||
|
|
||||||
// This constructor is used only by deserializer
|
// This constructor is used only by deserializer
|
||||||
private GlobalConfig() { }
|
private GlobalConfig() { }
|
||||||
|
|
||||||
internal static GlobalConfig Load(string filePath) {
|
internal static GlobalConfig Load(string filePath) {
|
||||||
if (string.IsNullOrEmpty(filePath)) {
|
if (string.IsNullOrEmpty(filePath)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(filePath));
|
Program.ArchiLogger.LogNullError(nameof(filePath));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,12 +119,12 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
globalConfig = JsonConvert.DeserializeObject<GlobalConfig>(File.ReadAllText(filePath));
|
globalConfig = JsonConvert.DeserializeObject<GlobalConfig>(File.ReadAllText(filePath));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalConfig == null) {
|
if (globalConfig == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(globalConfig));
|
Program.ArchiLogger.LogNullError(nameof(globalConfig));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,24 +135,24 @@ namespace ArchiSteamFarm {
|
|||||||
case ProtocolType.Udp:
|
case ProtocolType.Udp:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ASF.ArchiLogger.LogGenericWarning("Configured SteamProtocol is invalid: " + globalConfig.SteamProtocol);
|
Program.ArchiLogger.LogGenericWarning("Configured SteamProtocol is invalid: " + globalConfig.SteamProtocol);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 (globalConfig.MaxFarmingTime == 0) {
|
if (globalConfig.MaxFarmingTime == 0) {
|
||||||
ASF.ArchiLogger.LogGenericWarning("Configured MaxFarmingTime is invalid: " + globalConfig.MaxFarmingTime);
|
Program.ArchiLogger.LogGenericWarning("Configured MaxFarmingTime is invalid: " + globalConfig.MaxFarmingTime);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalConfig.FarmingDelay == 0) {
|
if (globalConfig.FarmingDelay == 0) {
|
||||||
ASF.ArchiLogger.LogGenericWarning("Configured FarmingDelay is invalid: " + globalConfig.FarmingDelay);
|
Program.ArchiLogger.LogGenericWarning("Configured FarmingDelay is invalid: " + globalConfig.FarmingDelay);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalConfig.HttpTimeout == 0) {
|
if (globalConfig.HttpTimeout == 0) {
|
||||||
ASF.ArchiLogger.LogGenericWarning("Configured HttpTimeout is invalid: " + globalConfig.HttpTimeout);
|
Program.ArchiLogger.LogGenericWarning("Configured HttpTimeout is invalid: " + globalConfig.HttpTimeout);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +160,7 @@ namespace ArchiSteamFarm {
|
|||||||
return globalConfig;
|
return globalConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort);
|
Program.ArchiLogger.LogGenericWarning("Configured WCFPort is invalid: " + globalConfig.WCFPort);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
|
internal readonly Guid Guid = Guid.NewGuid();
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
internal readonly InMemoryServerListProvider ServerListProvider = new InMemoryServerListProvider();
|
internal readonly InMemoryServerListProvider ServerListProvider = new InMemoryServerListProvider();
|
||||||
|
|
||||||
@@ -81,7 +84,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
internal static GlobalDatabase Load(string filePath) {
|
internal static GlobalDatabase Load(string filePath) {
|
||||||
if (string.IsNullOrEmpty(filePath)) {
|
if (string.IsNullOrEmpty(filePath)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(filePath));
|
Program.ArchiLogger.LogNullError(nameof(filePath));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,12 +97,12 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
globalDatabase = JsonConvert.DeserializeObject<GlobalDatabase>(File.ReadAllText(filePath), CustomSerializerSettings);
|
globalDatabase = JsonConvert.DeserializeObject<GlobalDatabase>(File.ReadAllText(filePath), CustomSerializerSettings);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (globalDatabase == null) {
|
if (globalDatabase == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(globalDatabase));
|
Program.ArchiLogger.LogNullError(nameof(globalDatabase));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +115,7 @@ namespace ArchiSteamFarm {
|
|||||||
private void Save() {
|
private void Save() {
|
||||||
string json = JsonConvert.SerializeObject(this, CustomSerializerSettings);
|
string json = JsonConvert.SerializeObject(this, CustomSerializerSettings);
|
||||||
if (string.IsNullOrEmpty(json)) {
|
if (string.IsNullOrEmpty(json)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(json));
|
Program.ArchiLogger.LogNullError(nameof(json));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +125,7 @@ namespace ArchiSteamFarm {
|
|||||||
File.WriteAllText(FilePath, json);
|
File.WriteAllText(FilePath, json);
|
||||||
break;
|
break;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
public Task UpdateServerListAsync(IEnumerable<IPEndPoint> endPoints) {
|
public Task UpdateServerListAsync(IEnumerable<IPEndPoint> endPoints) {
|
||||||
if (endPoints == null) {
|
if (endPoints == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(endPoints));
|
Program.ArchiLogger.LogNullError(nameof(endPoints));
|
||||||
return Task.Delay(0);
|
return Task.Delay(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,25 +67,25 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
|
|
||||||
HtmlNode htmlNode = HtmlDocument.DocumentNode.SelectSingleNode("//div[@class='tradeoffer']");
|
HtmlNode htmlNode = HtmlDocument.DocumentNode.SelectSingleNode("//div[@class='tradeoffer']");
|
||||||
if (htmlNode == null) {
|
if (htmlNode == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(htmlNode));
|
Program.ArchiLogger.LogNullError(nameof(htmlNode));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
string id = htmlNode.GetAttributeValue("id", null);
|
string id = htmlNode.GetAttributeValue("id", null);
|
||||||
if (string.IsNullOrEmpty(id)) {
|
if (string.IsNullOrEmpty(id)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(id));
|
Program.ArchiLogger.LogNullError(nameof(id));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = id.IndexOf('_');
|
int index = id.IndexOf('_');
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(index));
|
Program.ArchiLogger.LogNullError(nameof(index));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
if (id.Length <= index) {
|
if (id.Length <= index) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(id.Length));
|
Program.ArchiLogger.LogNullError(nameof(id.Length));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
return _TradeOfferID;
|
return _TradeOfferID;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogNullError(nameof(_TradeOfferID));
|
Program.ArchiLogger.LogNullError(nameof(_TradeOfferID));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,13 +131,13 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
|
|
||||||
HtmlNode htmlNode = HtmlDocument.DocumentNode.SelectSingleNode("//a/@data-miniprofile");
|
HtmlNode htmlNode = HtmlDocument.DocumentNode.SelectSingleNode("//a/@data-miniprofile");
|
||||||
if (htmlNode == null) {
|
if (htmlNode == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(htmlNode));
|
Program.ArchiLogger.LogNullError(nameof(htmlNode));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
string miniProfile = htmlNode.GetAttributeValue("data-miniprofile", null);
|
string miniProfile = htmlNode.GetAttributeValue("data-miniprofile", null);
|
||||||
if (string.IsNullOrEmpty(miniProfile)) {
|
if (string.IsNullOrEmpty(miniProfile)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(miniProfile));
|
Program.ArchiLogger.LogNullError(nameof(miniProfile));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
return _OtherSteamID3;
|
return _OtherSteamID3;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogNullError(nameof(_OtherSteamID3));
|
Program.ArchiLogger.LogNullError(nameof(_OtherSteamID3));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
|
|
||||||
set {
|
set {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(value));
|
Program.ArchiLogger.LogNullError(nameof(value));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,13 +237,13 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
|
|
||||||
set {
|
set {
|
||||||
if (string.IsNullOrEmpty(value)) {
|
if (string.IsNullOrEmpty(value)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(value));
|
Program.ArchiLogger.LogNullError(nameof(value));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint amount;
|
uint amount;
|
||||||
if (!uint.TryParse(value, out amount) || (amount == 0)) {
|
if (!uint.TryParse(value, out amount) || (amount == 0)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(amount));
|
Program.ArchiLogger.LogNullError(nameof(amount));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,13 +258,13 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
|
|
||||||
set {
|
set {
|
||||||
if (string.IsNullOrEmpty(value)) {
|
if (string.IsNullOrEmpty(value)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(value));
|
Program.ArchiLogger.LogNullError(nameof(value));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint appID;
|
uint appID;
|
||||||
if (!uint.TryParse(value, out appID) || (appID == 0)) {
|
if (!uint.TryParse(value, out appID) || (appID == 0)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(appID));
|
Program.ArchiLogger.LogNullError(nameof(appID));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,13 +278,13 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
|
|
||||||
set {
|
set {
|
||||||
if (string.IsNullOrEmpty(value)) {
|
if (string.IsNullOrEmpty(value)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(value));
|
Program.ArchiLogger.LogNullError(nameof(value));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong assetID;
|
ulong assetID;
|
||||||
if (!ulong.TryParse(value, out assetID) || (assetID == 0)) {
|
if (!ulong.TryParse(value, out assetID) || (assetID == 0)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(assetID));
|
Program.ArchiLogger.LogNullError(nameof(assetID));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
|
|
||||||
set {
|
set {
|
||||||
if (string.IsNullOrEmpty(value)) {
|
if (string.IsNullOrEmpty(value)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(value));
|
Program.ArchiLogger.LogNullError(nameof(value));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,13 +319,13 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
|
|
||||||
set {
|
set {
|
||||||
if (string.IsNullOrEmpty(value)) {
|
if (string.IsNullOrEmpty(value)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(value));
|
Program.ArchiLogger.LogNullError(nameof(value));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong contextID;
|
ulong contextID;
|
||||||
if (!ulong.TryParse(value, out contextID) || (contextID == 0)) {
|
if (!ulong.TryParse(value, out contextID) || (contextID == 0)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(contextID));
|
Program.ArchiLogger.LogNullError(nameof(contextID));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,19 +359,28 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
|
|
||||||
internal enum EType : byte {
|
internal enum EType : byte {
|
||||||
Unknown,
|
Unknown,
|
||||||
|
|
||||||
BoosterPack,
|
BoosterPack,
|
||||||
Coupon,
|
Coupon,
|
||||||
Gift,
|
|
||||||
SteamGems,
|
|
||||||
|
|
||||||
Emoticon,
|
Emoticon,
|
||||||
|
Gift,
|
||||||
FoilTradingCard,
|
FoilTradingCard,
|
||||||
ProfileBackground,
|
ProfileBackground,
|
||||||
TradingCard
|
TradingCard,
|
||||||
|
SteamGems
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||||
|
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
|
||||||
|
internal sealed class NewDiscoveryQueueResponse { // Deserialized from JSON
|
||||||
|
#pragma warning disable 649
|
||||||
|
[JsonProperty(PropertyName = "queue", Required = Required.Always)]
|
||||||
|
internal readonly HashSet<uint> Queue;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
private NewDiscoveryQueueResponse() { }
|
||||||
|
}
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||||
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
|
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
|
||||||
internal sealed class RedeemWalletResponse { // Deserialized from JSON
|
internal sealed class RedeemWalletResponse { // Deserialized from JSON
|
||||||
@@ -396,7 +405,7 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (OtherSteamID3 == 0) {
|
if (OtherSteamID3 == 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(OtherSteamID3));
|
Program.ArchiLogger.LogNullError(nameof(OtherSteamID3));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,7 +449,10 @@ namespace ArchiSteamFarm.JSON {
|
|||||||
foreach (Item item in ItemsToReceive) {
|
foreach (Item item in ItemsToReceive) {
|
||||||
Dictionary<Item.EType, uint> itemsPerType;
|
Dictionary<Item.EType, uint> itemsPerType;
|
||||||
if (!itemsToReceivePerGame.TryGetValue(item.RealAppID, out itemsPerType)) {
|
if (!itemsToReceivePerGame.TryGetValue(item.RealAppID, out itemsPerType)) {
|
||||||
itemsPerType = new Dictionary<Item.EType, uint> { [item.Type] = item.Amount };
|
itemsPerType = new Dictionary<Item.EType, uint> {
|
||||||
|
{ item.Type, item.Amount }
|
||||||
|
};
|
||||||
|
|
||||||
itemsToReceivePerGame[item.RealAppID] = itemsPerType;
|
itemsToReceivePerGame[item.RealAppID] = itemsPerType;
|
||||||
} else {
|
} else {
|
||||||
uint amount;
|
uint amount;
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static void OnConfigurationChanged(object sender, LoggingConfigurationChangedEventArgs e) {
|
private static void OnConfigurationChanged(object sender, LoggingConfigurationChangedEventArgs e) {
|
||||||
if ((sender == null) || (e == null)) {
|
if ((sender == null) || (e == null)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
Program.ArchiLogger.LogNullError(nameof(sender) + " || " + nameof(e));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ using SteamKit2;
|
|||||||
|
|
||||||
namespace ArchiSteamFarm {
|
namespace ArchiSteamFarm {
|
||||||
internal static class Program {
|
internal static class Program {
|
||||||
|
internal static readonly ArchiLogger ArchiLogger = new ArchiLogger(SharedInfo.ASF);
|
||||||
|
|
||||||
internal static bool IsWCFRunning => WCF.IsServerRunning;
|
internal static bool IsWCFRunning => WCF.IsServerRunning;
|
||||||
internal static GlobalConfig GlobalConfig { get; private set; }
|
internal static GlobalConfig GlobalConfig { get; private set; }
|
||||||
internal static GlobalDatabase GlobalDatabase { get; private set; }
|
internal static GlobalDatabase GlobalDatabase { get; private set; }
|
||||||
@@ -59,7 +61,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (GlobalConfig.Headless || !Runtime.IsUserInteractive) {
|
if (GlobalConfig.Headless || !Runtime.IsUserInteractive) {
|
||||||
ASF.ArchiLogger.LogGenericWarning("Received a request for user input, but process is running in headless mode!");
|
ArchiLogger.LogGenericWarning("Received a request for user input, but process is running in headless mode!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +98,7 @@ namespace ArchiSteamFarm {
|
|||||||
Console.Write("<" + botName + "> Please enter your 2 factor auth code from your authenticator app: ");
|
Console.Write("<" + botName + "> Please enter your 2 factor auth code from your authenticator app: ");
|
||||||
break;
|
break;
|
||||||
case ASF.EUserInputType.WCFHostname:
|
case ASF.EUserInputType.WCFHostname:
|
||||||
Console.Write("<" + botName + "> Please enter your WCF hostname: ");
|
Console.Write("<" + botName + "> Please enter your WCF host: ");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Console.Write("<" + botName + "> Please enter not documented yet value of \"" + userInputType + "\": ");
|
Console.Write("<" + botName + "> Please enter not documented yet value of \"" + userInputType + "\": ");
|
||||||
@@ -123,7 +125,7 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
Process.Start(Assembly.GetEntryAssembly().Location, string.Join(" ", Environment.GetCommandLineArgs().Skip(1)));
|
Process.Start(Assembly.GetEntryAssembly().Location, string.Join(" ", Environment.GetCommandLineArgs().Skip(1)));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShutdownResetEvent.Set();
|
ShutdownResetEvent.Set();
|
||||||
@@ -138,7 +140,7 @@ namespace ArchiSteamFarm {
|
|||||||
ShutdownResetEvent.Set();
|
ShutdownResetEvent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Init(string[] args) {
|
private static async Task Init(string[] args) {
|
||||||
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
|
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
|
||||||
TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler;
|
TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler;
|
||||||
|
|
||||||
@@ -169,10 +171,10 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Logging.InitLoggers();
|
Logging.InitLoggers();
|
||||||
ASF.ArchiLogger.LogGenericInfo("ASF V" + SharedInfo.Version);
|
ArchiLogger.LogGenericInfo("ASF V" + SharedInfo.Version);
|
||||||
|
|
||||||
if (!Runtime.IsRuntimeSupported) {
|
if (!Runtime.IsRuntimeSupported) {
|
||||||
ASF.ArchiLogger.LogGenericError("ASF detected unsupported runtime version, program might NOT run correctly in current environment. You're running it at your own risk!");
|
ArchiLogger.LogGenericError("ASF detected unsupported runtime version, program might NOT run correctly in current environment. You're running it at your own risk!");
|
||||||
Thread.Sleep(10000);
|
Thread.Sleep(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +195,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
// Parse post-init args
|
// Parse post-init args
|
||||||
if (args != null) {
|
if (args != null) {
|
||||||
ParsePostInitArgs(args);
|
await ParsePostInitArgs(args).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we ran ASF as a client, we're done by now
|
// If we ran ASF as a client, we're done by now
|
||||||
@@ -201,8 +203,8 @@ namespace ArchiSteamFarm {
|
|||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.CheckForUpdate().Wait();
|
await ASF.CheckForUpdate().ConfigureAwait(false);
|
||||||
ASF.InitBots();
|
await ASF.InitBots().ConfigureAwait(false);
|
||||||
ASF.InitFileWatcher();
|
ASF.InitFileWatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +213,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
GlobalConfig = GlobalConfig.Load(globalConfigFile);
|
GlobalConfig = GlobalConfig.Load(globalConfigFile);
|
||||||
if (GlobalConfig == null) {
|
if (GlobalConfig == null) {
|
||||||
ASF.ArchiLogger.LogGenericError("Global config could not be loaded, please make sure that " + globalConfigFile + " exists and is valid! Did you forget to read wiki?");
|
ArchiLogger.LogGenericError("Global config could not be loaded, please make sure that " + globalConfigFile + " exists and is valid! Did you forget to read wiki?");
|
||||||
Thread.Sleep(5000);
|
Thread.Sleep(5000);
|
||||||
Exit(1);
|
Exit(1);
|
||||||
}
|
}
|
||||||
@@ -220,7 +222,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
GlobalDatabase = GlobalDatabase.Load(globalDatabaseFile);
|
GlobalDatabase = GlobalDatabase.Load(globalDatabaseFile);
|
||||||
if (GlobalDatabase == null) {
|
if (GlobalDatabase == null) {
|
||||||
ASF.ArchiLogger.LogGenericError("Global database could not be loaded, if issue persists, please remove " + globalDatabaseFile + " in order to recreate database!");
|
ArchiLogger.LogGenericError("Global database could not be loaded, if issue persists, please remove " + globalDatabaseFile + " in order to recreate database!");
|
||||||
Thread.Sleep(5000);
|
Thread.Sleep(5000);
|
||||||
Exit(1);
|
Exit(1);
|
||||||
}
|
}
|
||||||
@@ -229,7 +231,7 @@ namespace ArchiSteamFarm {
|
|||||||
WebBrowser.Init();
|
WebBrowser.Init();
|
||||||
WCF.Init();
|
WCF.Init();
|
||||||
|
|
||||||
WebBrowser = new WebBrowser(ASF.ArchiLogger);
|
WebBrowser = new WebBrowser(ArchiLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool InitShutdownSequence() {
|
private static bool InitShutdownSequence() {
|
||||||
@@ -250,7 +252,7 @@ namespace ArchiSteamFarm {
|
|||||||
private static void Main(string[] args) {
|
private static void Main(string[] args) {
|
||||||
if (Runtime.IsUserInteractive) {
|
if (Runtime.IsUserInteractive) {
|
||||||
// App
|
// App
|
||||||
Init(args);
|
Init(args).Wait();
|
||||||
|
|
||||||
// Wait for signal to shutdown
|
// Wait for signal to shutdown
|
||||||
ShutdownResetEvent.Wait();
|
ShutdownResetEvent.Wait();
|
||||||
@@ -266,9 +268,9 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ParsePostInitArgs(IEnumerable<string> args) {
|
private static async Task ParsePostInitArgs(IEnumerable<string> args) {
|
||||||
if (args == null) {
|
if (args == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(args));
|
ArchiLogger.LogNullError(nameof(args));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +284,7 @@ namespace ArchiSteamFarm {
|
|||||||
case "--server":
|
case "--server":
|
||||||
Mode |= EMode.Server;
|
Mode |= EMode.Server;
|
||||||
WCF.StartServer();
|
WCF.StartServer();
|
||||||
ASF.InitBots();
|
await ASF.InitBots().ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (arg.StartsWith("--", StringComparison.Ordinal)) {
|
if (arg.StartsWith("--", StringComparison.Ordinal)) {
|
||||||
@@ -294,12 +296,11 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!Mode.HasFlag(EMode.Client)) {
|
if (!Mode.HasFlag(EMode.Client)) {
|
||||||
ASF.ArchiLogger.LogGenericWarning("Ignoring command because --client wasn't specified: " + arg);
|
ArchiLogger.LogGenericWarning("Ignoring command because --client wasn't specified: " + arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogGenericInfo("Command sent: " + arg);
|
ArchiLogger.LogGenericInfo("Response received: " + WCF.SendCommand(arg));
|
||||||
ASF.ArchiLogger.LogGenericInfo("Response received: " + WCF.SendCommand(arg));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,7 +308,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static void ParsePreInitArgs(IEnumerable<string> args) {
|
private static void ParsePreInitArgs(IEnumerable<string> args) {
|
||||||
if (args == null) {
|
if (args == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(args));
|
ArchiLogger.LogNullError(nameof(args));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,20 +336,20 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) {
|
private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) {
|
||||||
if (args?.ExceptionObject == null) {
|
if (args?.ExceptionObject == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(args) + " || " + nameof(args.ExceptionObject));
|
ArchiLogger.LogNullError(nameof(args) + " || " + nameof(args.ExceptionObject));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogFatalException((Exception) args.ExceptionObject);
|
ArchiLogger.LogFatalException((Exception) args.ExceptionObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) {
|
private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) {
|
||||||
if (args?.Exception == null) {
|
if (args?.Exception == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(args) + " || " + nameof(args.Exception));
|
ArchiLogger.LogNullError(nameof(args) + " || " + nameof(args.Exception));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogFatalException(args.Exception);
|
ArchiLogger.LogFatalException(args.Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
@@ -363,8 +364,13 @@ namespace ArchiSteamFarm {
|
|||||||
ServiceName = SharedInfo.ServiceName;
|
ServiceName = SharedInfo.ServiceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnStart(string[] args) => Task.Run(() => {
|
protected override void OnStart(string[] args) => Task.Run(async () => {
|
||||||
Init(args);
|
// Normally it'd make sense to use already provided string[] args parameter above
|
||||||
|
// However, that one doesn't seem to work when ASF is started as a service, it's always null
|
||||||
|
// Therefore, we will use Environment args in such case
|
||||||
|
string[] envArgs = Environment.GetCommandLineArgs();
|
||||||
|
await Init(envArgs).ConfigureAwait(false);
|
||||||
|
|
||||||
ShutdownResetEvent.Wait();
|
ShutdownResetEvent.Wait();
|
||||||
Stop();
|
Stop();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,38 +39,38 @@ namespace ArchiSteamFarm {
|
|||||||
if (IsRunningOnMono) {
|
if (IsRunningOnMono) {
|
||||||
Version monoVersion = GetMonoVersion();
|
Version monoVersion = GetMonoVersion();
|
||||||
if (monoVersion == null) {
|
if (monoVersion == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(monoVersion));
|
Program.ArchiLogger.LogNullError(nameof(monoVersion));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Version minMonoVersion = new Version(4, 6);
|
Version minMonoVersion = new Version(4, 6);
|
||||||
|
|
||||||
if (monoVersion >= minMonoVersion) {
|
if (monoVersion >= minMonoVersion) {
|
||||||
ASF.ArchiLogger.LogGenericInfo("Your Mono version is OK. Required: " + minMonoVersion + " | Found: " + monoVersion);
|
Program.ArchiLogger.LogGenericInfo("Your Mono version is OK. Required: " + minMonoVersion + " | Found: " + monoVersion);
|
||||||
_IsRuntimeSupported = true;
|
_IsRuntimeSupported = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogGenericWarning("Your Mono version is too old. Required: " + minMonoVersion + " | Found: " + monoVersion);
|
Program.ArchiLogger.LogGenericWarning("Your Mono version is too old. Required: " + minMonoVersion + " | Found: " + monoVersion);
|
||||||
_IsRuntimeSupported = false;
|
_IsRuntimeSupported = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Version netVersion = GetNetVersion();
|
Version netVersion = GetNetVersion();
|
||||||
if (netVersion == null) {
|
if (netVersion == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(netVersion));
|
Program.ArchiLogger.LogNullError(nameof(netVersion));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Version minNetVersion = new Version(4, 6, 1);
|
Version minNetVersion = new Version(4, 6, 1);
|
||||||
|
|
||||||
if (netVersion >= minNetVersion) {
|
if (netVersion >= minNetVersion) {
|
||||||
ASF.ArchiLogger.LogGenericInfo("Your .NET version is OK. Required: " + minNetVersion + " | Found: " + netVersion);
|
Program.ArchiLogger.LogGenericInfo("Your .NET version is OK. Required: " + minNetVersion + " | Found: " + netVersion);
|
||||||
_IsRuntimeSupported = true;
|
_IsRuntimeSupported = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogGenericWarning("Your .NET version is too old. Required: " + minNetVersion + " | Found: " + netVersion);
|
Program.ArchiLogger.LogGenericWarning("Your .NET version is too old. Required: " + minNetVersion + " | Found: " + netVersion);
|
||||||
_IsRuntimeSupported = false;
|
_IsRuntimeSupported = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -98,33 +98,34 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool RequiresTls12Testing => IsRunningOnMono;
|
||||||
|
|
||||||
private static readonly Type MonoRuntime = Type.GetType("Mono.Runtime");
|
private static readonly Type MonoRuntime = Type.GetType("Mono.Runtime");
|
||||||
|
|
||||||
private static bool? _IsRuntimeSupported;
|
private static bool? _IsRuntimeSupported;
|
||||||
|
|
||||||
private static bool? _IsUserInteractive;
|
private static bool? _IsUserInteractive;
|
||||||
|
|
||||||
private static Version GetMonoVersion() {
|
private static Version GetMonoVersion() {
|
||||||
if (MonoRuntime == null) {
|
if (MonoRuntime == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(MonoRuntime));
|
Program.ArchiLogger.LogNullError(nameof(MonoRuntime));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodInfo displayName = MonoRuntime.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
|
MethodInfo displayName = MonoRuntime.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
if (displayName == null) {
|
if (displayName == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(displayName));
|
Program.ArchiLogger.LogNullError(nameof(displayName));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
string versionString = (string) displayName.Invoke(null, null);
|
string versionString = (string) displayName.Invoke(null, null);
|
||||||
if (string.IsNullOrEmpty(versionString)) {
|
if (string.IsNullOrEmpty(versionString)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(versionString));
|
Program.ArchiLogger.LogNullError(nameof(versionString));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = versionString.IndexOf(' ');
|
int index = versionString.IndexOf(' ');
|
||||||
if (index <= 0) {
|
if (index <= 0) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(index));
|
Program.ArchiLogger.LogNullError(nameof(index));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ namespace ArchiSteamFarm {
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogNullError(nameof(version));
|
Program.ArchiLogger.LogNullError(nameof(version));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,18 +144,18 @@ namespace ArchiSteamFarm {
|
|||||||
uint release;
|
uint release;
|
||||||
using (RegistryKey registryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\")) {
|
using (RegistryKey registryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4\\Full\\")) {
|
||||||
if (registryKey == null) {
|
if (registryKey == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(registryKey));
|
Program.ArchiLogger.LogNullError(nameof(registryKey));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
object releaseObj = registryKey.GetValue("Release");
|
object releaseObj = registryKey.GetValue("Release");
|
||||||
if (releaseObj == null) {
|
if (releaseObj == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(releaseObj));
|
Program.ArchiLogger.LogNullError(nameof(releaseObj));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!uint.TryParse(releaseObj.ToString(), out release) || (release == 0)) {
|
if (!uint.TryParse(releaseObj.ToString(), out release) || (release == 0)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(release));
|
Program.ArchiLogger.LogNullError(nameof(release));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ namespace ArchiSteamFarm {
|
|||||||
internal const string LogFile = "log.txt";
|
internal const string LogFile = "log.txt";
|
||||||
internal const string ServiceDescription = "ASF is an application that allows you to farm steam cards using multiple steam accounts simultaneously.";
|
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 ServiceName = "ArchiSteamFarm";
|
||||||
internal const string StatisticsServer = "https://asf.justarchi.net";
|
internal const string StatisticsServer = "asf.justarchi.net";
|
||||||
internal const string VersionNumber = "2.1.7.1";
|
internal const string VersionNumber = "2.2.0.0";
|
||||||
|
|
||||||
internal static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
internal static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SteamKit2;
|
using SteamKit2;
|
||||||
@@ -32,11 +33,21 @@ namespace ArchiSteamFarm {
|
|||||||
internal sealed class Statistics : IDisposable {
|
internal sealed class Statistics : IDisposable {
|
||||||
private const byte MinHeartBeatTTL = 5; // Minimum amount of minutes we must wait before sending next HeartBeat
|
private const byte MinHeartBeatTTL = 5; // Minimum amount of minutes we must wait before sending next HeartBeat
|
||||||
|
|
||||||
|
private static readonly SemaphoreSlim InitializationSemaphore = new SemaphoreSlim(1);
|
||||||
|
|
||||||
|
private static string _URL;
|
||||||
|
|
||||||
private readonly Bot Bot;
|
private readonly Bot Bot;
|
||||||
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
|
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
|
||||||
|
|
||||||
|
private bool HasAutomatedTrading => Bot.HasMobileAuthenticator && Bot.HasValidApiKey;
|
||||||
|
private bool SteamTradeMatcher => Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher);
|
||||||
|
|
||||||
private string LastAvatarHash;
|
private string LastAvatarHash;
|
||||||
private DateTime LastHeartBeat = DateTime.MinValue;
|
private DateTime LastHeartBeat = DateTime.MinValue;
|
||||||
|
private bool? LastMatchEverything;
|
||||||
|
private string LastNickname;
|
||||||
|
private bool ShouldSendHeartBeats;
|
||||||
|
|
||||||
internal Statistics(Bot bot) {
|
internal Statistics(Bot bot) {
|
||||||
if (bot == null) {
|
if (bot == null) {
|
||||||
@@ -49,20 +60,21 @@ namespace ArchiSteamFarm {
|
|||||||
public void Dispose() => Semaphore.Dispose();
|
public void Dispose() => Semaphore.Dispose();
|
||||||
|
|
||||||
internal async Task OnHeartBeat() {
|
internal async Task OnHeartBeat() {
|
||||||
if (DateTime.Now < LastHeartBeat.AddMinutes(MinHeartBeatTTL)) {
|
if (!ShouldSendHeartBeats || (DateTime.Now < LastHeartBeat.AddMinutes(MinHeartBeatTTL))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Semaphore.WaitAsync().ConfigureAwait(false);
|
await Semaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (DateTime.Now < LastHeartBeat.AddMinutes(MinHeartBeatTTL)) {
|
if (!ShouldSendHeartBeats || (DateTime.Now < LastHeartBeat.AddMinutes(MinHeartBeatTTL))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string request = SharedInfo.StatisticsServer + "/api/HeartBeat";
|
string request = await GetURL().ConfigureAwait(false) + "/api/HeartBeat";
|
||||||
Dictionary<string, string> data = new Dictionary<string, string>(1) {
|
Dictionary<string, string> data = new Dictionary<string, string>(2) {
|
||||||
{ "SteamID", Bot.SteamID.ToString() }
|
{ "SteamID", Bot.SteamID.ToString() },
|
||||||
|
{ "Guid", Program.GlobalDatabase.Guid.ToString("N") }
|
||||||
};
|
};
|
||||||
|
|
||||||
// We don't need retry logic here
|
// We don't need retry logic here
|
||||||
@@ -74,58 +86,110 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task OnLoggedOn() {
|
internal async Task OnLoggedOn() => await Bot.ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID).ConfigureAwait(false);
|
||||||
await Bot.ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID).ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Semaphore.WaitAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const string request = SharedInfo.StatisticsServer + "/api/LoggedOn";
|
|
||||||
Dictionary<string, string> data = new Dictionary<string, string>(4) {
|
|
||||||
{ "SteamID", Bot.SteamID.ToString() },
|
|
||||||
{ "HasAutomatedTrading", Bot.HasMobileAuthenticator && Bot.HasValidApiKey ? "1" : "0" },
|
|
||||||
{ "SteamTradeMatcher", Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher) ? "1" : "0" },
|
|
||||||
{ "MatchEverything", Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything) ? "1" : "0" }
|
|
||||||
};
|
|
||||||
|
|
||||||
// We don't need retry logic here
|
|
||||||
await Program.WebBrowser.UrlPost(request, data).ConfigureAwait(false);
|
|
||||||
} finally {
|
|
||||||
Semaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal async Task OnPersonaState(SteamFriends.PersonaStateCallback callback) {
|
internal async Task OnPersonaState(SteamFriends.PersonaStateCallback callback) {
|
||||||
if (callback == null) {
|
if (callback == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(callback));
|
Program.ArchiLogger.LogNullError(nameof(callback));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string avatarHash = BitConverter.ToString(callback.AvatarHash).Replace("-", "").ToLowerInvariant();
|
// Don't announce if we don't meet conditions
|
||||||
if (!string.IsNullOrEmpty(LastAvatarHash) && avatarHash.Equals(LastAvatarHash)) {
|
if (!HasAutomatedTrading || !SteamTradeMatcher) {
|
||||||
|
ShouldSendHeartBeats = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string nickname = callback.Name ?? "";
|
||||||
|
string avatarHash = "";
|
||||||
|
|
||||||
|
if ((callback.AvatarHash != null) && (callback.AvatarHash.Length > 0) && callback.AvatarHash.Any(singleByte => singleByte != 0)) {
|
||||||
|
avatarHash = BitConverter.ToString(callback.AvatarHash).Replace("-", "").ToLowerInvariant();
|
||||||
|
if (avatarHash.Equals("0000000000000000000000000000000000000000")) {
|
||||||
|
avatarHash = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matchEverything = Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything);
|
||||||
|
|
||||||
|
// Skip announcing if we already announced this bot with the same data
|
||||||
|
if (!string.IsNullOrEmpty(LastNickname) && nickname.Equals(LastNickname) && !string.IsNullOrEmpty(LastAvatarHash) && avatarHash.Equals(LastAvatarHash) && LastMatchEverything.HasValue && (matchEverything == LastMatchEverything.Value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Semaphore.WaitAsync().ConfigureAwait(false);
|
await Semaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!string.IsNullOrEmpty(LastAvatarHash) && avatarHash.Equals(LastAvatarHash)) {
|
// Skip announcing if we already announced this bot with the same data
|
||||||
|
if (!string.IsNullOrEmpty(LastNickname) && nickname.Equals(LastNickname) && !string.IsNullOrEmpty(LastAvatarHash) && avatarHash.Equals(LastAvatarHash) && LastMatchEverything.HasValue && (matchEverything == LastMatchEverything.Value)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const string request = SharedInfo.StatisticsServer + "/api/PersonaState";
|
// Even if following request fails, we want to send HeartBeats regardless
|
||||||
Dictionary<string, string> data = new Dictionary<string, string>(2) {
|
ShouldSendHeartBeats = true;
|
||||||
|
|
||||||
|
string request = await GetURL().ConfigureAwait(false) + "/api/Announce";
|
||||||
|
Dictionary<string, string> data = new Dictionary<string, string>(5) {
|
||||||
{ "SteamID", Bot.SteamID.ToString() },
|
{ "SteamID", Bot.SteamID.ToString() },
|
||||||
{ "AvatarHash", avatarHash }
|
{ "Guid", Program.GlobalDatabase.Guid.ToString("N") },
|
||||||
|
{ "Nickname", nickname },
|
||||||
|
{ "AvatarHash", avatarHash },
|
||||||
|
{ "MatchEverything", matchEverything ? "1" : "0" }
|
||||||
};
|
};
|
||||||
|
|
||||||
// We don't need retry logic here
|
// We don't need retry logic here
|
||||||
if (await Program.WebBrowser.UrlPost(request, data).ConfigureAwait(false)) {
|
if (await Program.WebBrowser.UrlPost(request, data).ConfigureAwait(false)) {
|
||||||
|
LastNickname = nickname;
|
||||||
LastAvatarHash = avatarHash;
|
LastAvatarHash = avatarHash;
|
||||||
|
LastMatchEverything = matchEverything;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Semaphore.Release();
|
Semaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task<string> GetURL() {
|
||||||
|
if (!string.IsNullOrEmpty(_URL)) {
|
||||||
|
return _URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our statistics server is using TLS 1.2 encryption method, which is not supported e.g. by older versions of Mono
|
||||||
|
// That's not a problem, as we support HTTP too, but of course we prefer more secure HTTPS if possible
|
||||||
|
// Because of that, this function is responsible for finding which URL should be used for accessing the server
|
||||||
|
|
||||||
|
// If our runtime doesn't require TLS 1.2 tests, skip the rest entirely, just use HTTPS
|
||||||
|
const string httpsURL = "https://" + SharedInfo.StatisticsServer;
|
||||||
|
if (!Runtime.RequiresTls12Testing) {
|
||||||
|
_URL = httpsURL;
|
||||||
|
return _URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
await InitializationSemaphore.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!string.IsNullOrEmpty(_URL)) {
|
||||||
|
return _URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we connect using HTTPS, use HTTPS as default version
|
||||||
|
if (await Program.WebBrowser.UrlPost(httpsURL + "/api/ConnectionTest").ConfigureAwait(false)) {
|
||||||
|
_URL = httpsURL;
|
||||||
|
return _URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we connect using HTTP, use HTTP as default version instead
|
||||||
|
const string httpURL = "http://" + SharedInfo.StatisticsServer;
|
||||||
|
if (await Program.WebBrowser.UrlPost(httpURL + "/api/ConnectionTest").ConfigureAwait(false)) {
|
||||||
|
_URL = httpURL;
|
||||||
|
return _URL;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
InitializationSemaphore.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't manage to establish connection through any of the above, return HTTPS, but don't record it
|
||||||
|
// We might need to re-run this function in the future
|
||||||
|
return httpsURL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
176
ArchiSteamFarm/SteamSaleEvent.cs
Normal file
176
ArchiSteamFarm/SteamSaleEvent.cs
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using HtmlAgilityPack;
|
||||||
|
|
||||||
|
namespace ArchiSteamFarm {
|
||||||
|
internal sealed class SteamSaleEvent : IDisposable {
|
||||||
|
private static readonly DateTime SaleEndingDateUtc = new DateTime(2017, 1, 2, 18, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
private readonly Bot Bot;
|
||||||
|
private readonly Timer SteamAwardsTimer;
|
||||||
|
private readonly Timer SteamDiscoveryQueueTimer;
|
||||||
|
|
||||||
|
internal SteamSaleEvent(Bot bot) {
|
||||||
|
if (bot == null) {
|
||||||
|
throw new ArgumentNullException(nameof(bot));
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot = bot;
|
||||||
|
|
||||||
|
if (DateTime.UtcNow >= SaleEndingDateUtc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SteamAwardsTimer = new Timer(
|
||||||
|
async e => await VoteForSteamAwards().ConfigureAwait(false),
|
||||||
|
null,
|
||||||
|
TimeSpan.FromMinutes(1 + 0.2 * Bot.Bots.Count), // Delay
|
||||||
|
TimeSpan.FromHours(6.1) // Period
|
||||||
|
);
|
||||||
|
|
||||||
|
SteamDiscoveryQueueTimer = new Timer(
|
||||||
|
async e => await ExploreDiscoveryQueue().ConfigureAwait(false),
|
||||||
|
null,
|
||||||
|
TimeSpan.FromMinutes(1 + 0.2 * Bot.Bots.Count), // Delay
|
||||||
|
TimeSpan.FromHours(6.1) // Period
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
SteamAwardsTimer?.Dispose();
|
||||||
|
SteamDiscoveryQueueTimer?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExploreDiscoveryQueue() {
|
||||||
|
if (DateTime.UtcNow >= SaleEndingDateUtc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Bot.ArchiWebHandler.Ready) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Started!");
|
||||||
|
|
||||||
|
for (byte i = 0; (i < 3) && !(await IsDiscoveryQueueEmpty().ConfigureAwait(false)).GetValueOrDefault(); i++) {
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Getting new queue...");
|
||||||
|
HashSet<uint> queue = await Bot.ArchiWebHandler.GenerateNewDiscoveryQueue().ConfigureAwait(false);
|
||||||
|
if (queue == null) {
|
||||||
|
Bot.ArchiLogger.LogGenericWarning("Aborting due to error!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("We got new queue, clearing...");
|
||||||
|
foreach (uint queuedAppID in queue) {
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Clearing " + queuedAppID + "...");
|
||||||
|
if (await Bot.ArchiWebHandler.ClearFromDiscoveryQueue(queuedAppID).ConfigureAwait(false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot.ArchiLogger.LogGenericWarning("Aborting due to error!");
|
||||||
|
i = byte.MaxValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Done!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool?> IsDiscoveryQueueEmpty() {
|
||||||
|
if (!Bot.ArchiWebHandler.Ready) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Checking if discovery queue is empty...");
|
||||||
|
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetDiscoveryQueuePage().ConfigureAwait(false);
|
||||||
|
if (htmlDocument == null) {
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Could not get discovery queue page, returning null");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HtmlNode htmlNode = htmlDocument.DocumentNode.SelectSingleNode("//div[@class='subtext']");
|
||||||
|
if (htmlNode == null) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(htmlNode));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string text = htmlNode.InnerText;
|
||||||
|
if (!string.IsNullOrEmpty(text)) {
|
||||||
|
// It'd make more sense to check "Come back tomorrow", but it might not cover out-of-the-event queue
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Our text is: " + text);
|
||||||
|
return !text.StartsWith("You can get ", StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(text));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task VoteForSteamAwards() {
|
||||||
|
if (DateTime.UtcNow >= SaleEndingDateUtc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Bot.ArchiWebHandler.Ready) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Getting SteamAwards page...");
|
||||||
|
HtmlDocument htmlDocument = await Bot.ArchiWebHandler.GetSteamAwardsPage().ConfigureAwait(false);
|
||||||
|
|
||||||
|
HtmlNodeCollection nominationsNodes = htmlDocument?.DocumentNode.SelectNodes("//div[@class='vote_nominations store_horizontal_autoslider']");
|
||||||
|
if (nominationsNodes == null) {
|
||||||
|
// Event ended, error or likewise
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Could not get SteamAwards page, returning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (HtmlNode nominationsNode in nominationsNodes) {
|
||||||
|
HtmlNode myVoteNode = nominationsNode.SelectSingleNode("./div[@class='vote_nomination your_vote']");
|
||||||
|
if (myVoteNode != null) {
|
||||||
|
// Already voted
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("We voted already, nothing to do");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string voteIDText = nominationsNode.GetAttributeValue("data-voteid", null);
|
||||||
|
if (string.IsNullOrEmpty(voteIDText)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(voteIDText));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte voteID;
|
||||||
|
if (!byte.TryParse(voteIDText, out voteID) || (voteID == 0)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(voteID));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HtmlNodeCollection voteNodes = nominationsNode.SelectNodes("./div[@class='vote_nomination ']");
|
||||||
|
if (voteNodes == null) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(voteNodes));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Random a game we'll actually vote for, we don't want to make GabeN angry by rigging votes...
|
||||||
|
HtmlNode voteNode = voteNodes[Utilities.RandomNext(voteNodes.Count)];
|
||||||
|
|
||||||
|
string appIDText = voteNode.GetAttributeValue("data-vote-appid", null);
|
||||||
|
if (string.IsNullOrEmpty(appIDText)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(appIDText));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint appID;
|
||||||
|
if (!uint.TryParse(appIDText, out appID) || (appID == 0)) {
|
||||||
|
Bot.ArchiLogger.LogNullError(nameof(appID));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Voting in #" + voteID + " for " + appID + "...");
|
||||||
|
await Bot.ArchiWebHandler.SteamAwardsVote(voteID, appID).ConfigureAwait(false);
|
||||||
|
Bot.ArchiLogger.LogGenericDebug("Done!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -110,7 +110,7 @@ namespace ArchiSteamFarm {
|
|||||||
if (Bot.HasMobileAuthenticator) {
|
if (Bot.HasMobileAuthenticator) {
|
||||||
HashSet<ulong> acceptedWithItemLoseTradeIDs = new HashSet<ulong>(results.Where(result => (result != null) && (result.Result == ParseTradeResult.EResult.AcceptedWithItemLose)).Select(result => result.TradeID));
|
HashSet<ulong> acceptedWithItemLoseTradeIDs = new HashSet<ulong>(results.Where(result => (result != null) && (result.Result == ParseTradeResult.EResult.AcceptedWithItemLose)).Select(result => result.TradeID));
|
||||||
if (acceptedWithItemLoseTradeIDs.Count > 0) {
|
if (acceptedWithItemLoseTradeIDs.Count > 0) {
|
||||||
await Task.Delay(1000).ConfigureAwait(false); // Sometimes we can be too fast for Steam servers to generate confirmations, wait a short moment
|
await Task.Delay(3000).ConfigureAwait(false); // Sometimes we can be too fast for Steam servers to generate confirmations, wait a short moment
|
||||||
await Bot.AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, 0, acceptedWithItemLoseTradeIDs).ConfigureAwait(false);
|
await Bot.AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, 0, acceptedWithItemLoseTradeIDs).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,7 +230,7 @@ namespace ArchiSteamFarm {
|
|||||||
// Now check if it's worth for us to do the trade
|
// Now check if it's worth for us to do the trade
|
||||||
await LimitInventoryRequestsAsync().ConfigureAwait(false);
|
await LimitInventoryRequestsAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
HashSet<Steam.Item> inventory = await Bot.ArchiWebHandler.GetMySteamInventory(false).ConfigureAwait(false);
|
HashSet<Steam.Item> inventory = await Bot.ArchiWebHandler.GetMySteamInventory(false, new HashSet<Steam.Item.EType> { Steam.Item.EType.TradingCard }).ConfigureAwait(false);
|
||||||
if ((inventory == null) || (inventory.Count == 0)) {
|
if ((inventory == null) || (inventory.Count == 0)) {
|
||||||
return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.AcceptedWithItemLose); // OK, assume that this trade is valid, we can't check our EQ
|
return new ParseTradeResult(tradeOffer.TradeOfferID, ParseTradeResult.EResult.AcceptedWithItemLose); // OK, assume that this trade is valid, we can't check our EQ
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,13 +30,15 @@ using System.Runtime.CompilerServices;
|
|||||||
|
|
||||||
namespace ArchiSteamFarm {
|
namespace ArchiSteamFarm {
|
||||||
internal static class Utilities {
|
internal static class Utilities {
|
||||||
|
private static readonly Random Random = new Random();
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
[SuppressMessage("ReSharper", "UnusedParameter.Global")]
|
[SuppressMessage("ReSharper", "UnusedParameter.Global")]
|
||||||
internal static void Forget(this object obj) { }
|
internal static void Forget(this object obj) { }
|
||||||
|
|
||||||
internal static string GetCookieValue(this CookieContainer cookieContainer, string url, string name) {
|
internal static string GetCookieValue(this CookieContainer cookieContainer, string url, string name) {
|
||||||
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(name)) {
|
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(name)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(url) + " || " + nameof(name));
|
Program.ArchiLogger.LogNullError(nameof(url) + " || " + nameof(name));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,14 +47,29 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
uri = new Uri(url);
|
uri = new Uri(url);
|
||||||
} catch (UriFormatException e) {
|
} catch (UriFormatException e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
CookieCollection cookies = cookieContainer.GetCookies(uri);
|
CookieCollection cookies = cookieContainer.GetCookies(uri);
|
||||||
return cookies.Count == 0 ? null : (from Cookie cookie in cookies where cookie.Name.Equals(name) select cookie.Value).FirstOrDefault();
|
return cookies.Count != 0 ? (from Cookie cookie in cookies where cookie.Name.Equals(name) select cookie.Value).FirstOrDefault() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static uint GetUnixTime() => (uint) DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
internal static uint GetUnixTime() => (uint) DateTimeOffset.Now.ToUnixTimeSeconds();
|
||||||
|
|
||||||
|
internal static int RandomNext(int maxWithout) {
|
||||||
|
if (maxWithout <= 0) {
|
||||||
|
Program.ArchiLogger.LogNullError(nameof(maxWithout));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxWithout == 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (Random) {
|
||||||
|
return Random.Next(maxWithout);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,6 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.ServiceModel;
|
using System.ServiceModel;
|
||||||
using System.ServiceModel.Channels;
|
using System.ServiceModel.Channels;
|
||||||
using System.ServiceModel.Description;
|
|
||||||
|
|
||||||
namespace ArchiSteamFarm {
|
namespace ArchiSteamFarm {
|
||||||
[ServiceContract]
|
[ServiceContract]
|
||||||
@@ -39,7 +38,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class WCF : IWCF, IDisposable {
|
internal sealed class WCF : IWCF, IDisposable {
|
||||||
private static string URL = "http://localhost:1242/ASF";
|
private static string URL = "net.tcp://127.0.0.1:1242/ASF";
|
||||||
|
|
||||||
internal bool IsServerRunning => ServiceHost != null;
|
internal bool IsServerRunning => ServiceHost != null;
|
||||||
|
|
||||||
@@ -55,7 +54,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
public string HandleCommand(string input) {
|
public string HandleCommand(string input) {
|
||||||
if (string.IsNullOrEmpty(input)) {
|
if (string.IsNullOrEmpty(input)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(input));
|
Program.ArchiLogger.LogNullError(nameof(input));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,31 +68,36 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
string command = "!" + input;
|
string command = "!" + input;
|
||||||
string output = bot.Response(Program.GlobalConfig.SteamOwnerID, command).Result; // TODO: This should be asynchronous
|
|
||||||
|
|
||||||
ASF.ArchiLogger.LogGenericInfo("Answered to command: " + input + " with: " + output);
|
// TODO: This should be asynchronous, but for some reason Mono doesn't return any WCF output if it is
|
||||||
|
// We must keep it synchronous until either Mono gets fixed, or culprit for freeze located (and corrected)
|
||||||
|
string output = bot.Response(Program.GlobalConfig.SteamOwnerID, command).Result;
|
||||||
|
|
||||||
|
Program.ArchiLogger.LogGenericInfo("Answered to WCF command: " + input + " with: " + output);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Init() {
|
internal static void Init() {
|
||||||
if (string.IsNullOrEmpty(Program.GlobalConfig.WCFHostname)) {
|
if (string.IsNullOrEmpty(Program.GlobalConfig.WCFHost)) {
|
||||||
Program.GlobalConfig.WCFHostname = Program.GetUserInput(ASF.EUserInputType.WCFHostname);
|
Program.GlobalConfig.WCFHost = Program.GetUserInput(ASF.EUserInputType.WCFHostname);
|
||||||
if (string.IsNullOrEmpty(Program.GlobalConfig.WCFHostname)) {
|
if (string.IsNullOrEmpty(Program.GlobalConfig.WCFHost)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
URL = "http://" + Program.GlobalConfig.WCFHostname + ":" + Program.GlobalConfig.WCFPort + "/ASF";
|
URL = "net.tcp://" + Program.GlobalConfig.WCFHost + ":" + Program.GlobalConfig.WCFPort + "/ASF";
|
||||||
}
|
}
|
||||||
|
|
||||||
internal string SendCommand(string input) {
|
internal string SendCommand(string input) {
|
||||||
if (string.IsNullOrEmpty(input)) {
|
if (string.IsNullOrEmpty(input)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(input));
|
Program.ArchiLogger.LogNullError(nameof(input));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Program.ArchiLogger.LogGenericInfo("Sending command: " + input + " to WCF server on " + URL + "...");
|
||||||
|
|
||||||
if (Client == null) {
|
if (Client == null) {
|
||||||
Client = new Client(new BasicHttpBinding(), new EndpointAddress(URL));
|
Client = new Client(new NetTcpBinding { Security = { Mode = SecurityMode.None } }, new EndpointAddress(URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Client.HandleCommand(input);
|
return Client.HandleCommand(input);
|
||||||
@@ -104,23 +108,19 @@ namespace ArchiSteamFarm {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogGenericInfo("Starting WCF server...");
|
Program.ArchiLogger.LogGenericInfo("Starting WCF server on " + URL + "...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ServiceHost = new ServiceHost(typeof(WCF), new Uri(URL));
|
ServiceHost = new ServiceHost(typeof(WCF), new Uri(URL));
|
||||||
|
ServiceHost.AddServiceEndpoint(typeof(IWCF), new NetTcpBinding { Security = { Mode = SecurityMode.None } }, string.Empty);
|
||||||
ServiceHost.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
|
|
||||||
|
|
||||||
ServiceHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
|
|
||||||
ServiceHost.AddServiceEndpoint(typeof(IWCF), new BasicHttpBinding(), string.Empty);
|
|
||||||
|
|
||||||
ServiceHost.Open();
|
ServiceHost.Open();
|
||||||
ASF.ArchiLogger.LogGenericInfo("WCF server ready!");
|
|
||||||
|
Program.ArchiLogger.LogGenericInfo("WCF server ready!");
|
||||||
} catch (AddressAccessDeniedException) {
|
} catch (AddressAccessDeniedException) {
|
||||||
ASF.ArchiLogger.LogGenericError("WCF service could not be started because of AddressAccessDeniedException!");
|
Program.ArchiLogger.LogGenericError("WCF service could not be started because of AddressAccessDeniedException!");
|
||||||
ASF.ArchiLogger.LogGenericWarning("If you want to use WCF service provided by ASF, consider starting ASF as administrator, or giving proper permissions!");
|
Program.ArchiLogger.LogGenericWarning("If you want to use WCF service provided by ASF, consider starting ASF as administrator, or giving proper permissions!");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
ServiceHost.Close();
|
ServiceHost.Close();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,14 +158,14 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
internal string HandleCommand(string input) {
|
internal string HandleCommand(string input) {
|
||||||
if (string.IsNullOrEmpty(input)) {
|
if (string.IsNullOrEmpty(input)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(input));
|
Program.ArchiLogger.LogNullError(nameof(input));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Channel.HandleCommand(input);
|
return Channel.HandleCommand(input);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
Program.ArchiLogger.LogGenericException(e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
||||||
|
ArchiLogger.LogGenericDebug("Failing request: " + request);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +122,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
||||||
|
ArchiLogger.LogGenericDebug("Failing request: " + request);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +142,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
||||||
|
ArchiLogger.LogGenericDebug("Failing request: " + request);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +181,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
||||||
|
ArchiLogger.LogGenericDebug("Failing request: " + request);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +201,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
||||||
|
ArchiLogger.LogGenericDebug("Failing request: " + request);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +221,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
||||||
|
ArchiLogger.LogGenericDebug("Failing request: " + request);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,6 +252,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
||||||
|
ArchiLogger.LogGenericDebug("Failing request: " + request);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,6 +341,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
||||||
|
ArchiLogger.LogGenericDebug("Failing request: " + request);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,6 +478,7 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries");
|
||||||
|
ArchiLogger.LogGenericDebug("Failing request: " + request);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,10 +497,6 @@ namespace ArchiSteamFarm {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.StartsWith("https://", StringComparison.Ordinal) && Program.GlobalConfig.ForceHttp) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpResponseMessage responseMessage;
|
HttpResponseMessage responseMessage;
|
||||||
using (HttpRequestMessage requestMessage = new HttpRequestMessage(httpMethod, request)) {
|
using (HttpRequestMessage requestMessage = new HttpRequestMessage(httpMethod, request)) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
@@ -512,7 +517,7 @@ namespace ArchiSteamFarm {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// This exception is really common, don't bother with it unless debug mode is enabled
|
// This exception is really common, don't bother with it unless debug mode is enabled
|
||||||
if (Debugging.IsDebugBuild || Program.GlobalConfig.Debug) {
|
if (Debugging.IsDebugBuild || Program.GlobalConfig.Debug) {
|
||||||
ArchiLogger.LogGenericException(e);
|
ArchiLogger.LogGenericDebugException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -528,9 +533,9 @@ namespace ArchiSteamFarm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Debugging.IsDebugBuild || Program.GlobalConfig.Debug) {
|
if (Debugging.IsDebugBuild || Program.GlobalConfig.Debug) {
|
||||||
ArchiLogger.LogGenericError("Request: " + request + " failed!");
|
ArchiLogger.LogGenericDebug("Request: " + request + " failed!");
|
||||||
ArchiLogger.LogGenericError("Status code: " + responseMessage.StatusCode);
|
ArchiLogger.LogGenericDebug("Status code: " + responseMessage.StatusCode);
|
||||||
ArchiLogger.LogGenericError("Content: " + Environment.NewLine + await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false));
|
ArchiLogger.LogGenericDebug("Content: " + Environment.NewLine + await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
responseMessage.Dispose();
|
responseMessage.Dispose();
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
{
|
{
|
||||||
"Debug": false,
|
"AutoRestart": true,
|
||||||
"Headless": false,
|
"AutoUpdates": true,
|
||||||
"AutoUpdates": true,
|
"Blacklist": [
|
||||||
"AutoRestart": true,
|
267420,
|
||||||
"UpdateChannel": 1,
|
303700,
|
||||||
"SteamProtocol": 6,
|
335590,
|
||||||
"SteamOwnerID": 0,
|
368020,
|
||||||
"MaxFarmingTime": 10,
|
425280,
|
||||||
"IdleFarmingPeriod": 3,
|
480730,
|
||||||
"FarmingDelay": 15,
|
566020
|
||||||
"LoginLimiterDelay": 10,
|
],
|
||||||
"InventoryLimiterDelay": 3,
|
"Debug": false,
|
||||||
"GiftsLimiterDelay": 1,
|
"FarmingDelay": 15,
|
||||||
"MaxTradeHoldDuration": 15,
|
"GiftsLimiterDelay": 1,
|
||||||
"ForceHttp": false,
|
"Headless": false,
|
||||||
"HttpTimeout": 60,
|
"HttpTimeout": 60,
|
||||||
"WCFHostname": "localhost",
|
"IdleFarmingPeriod": 3,
|
||||||
"WCFPort": 1242,
|
"InventoryLimiterDelay": 3,
|
||||||
"Statistics": true,
|
"LoginLimiterDelay": 10,
|
||||||
"Blacklist": [
|
"MaxFarmingTime": 10,
|
||||||
267420,
|
"MaxTradeHoldDuration": 15,
|
||||||
303700,
|
"Statistics": true,
|
||||||
335590,
|
"SteamOwnerID": 0,
|
||||||
368020,
|
"SteamProtocol": 6,
|
||||||
425280,
|
"UpdateChannel": 1,
|
||||||
480730
|
"WCFHost": "127.0.0.1",
|
||||||
]
|
"WCFPort": 1242
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,33 @@
|
|||||||
{
|
{
|
||||||
"Enabled": false,
|
"AcceptConfirmationsPeriod": 0,
|
||||||
"Paused": false,
|
"AcceptGifts": false,
|
||||||
"SteamLogin": null,
|
"CardDropsRestricted": true,
|
||||||
"SteamPassword": null,
|
"CustomGamePlayedWhileFarming": null,
|
||||||
"PasswordFormat": 0,
|
"CustomGamePlayedWhileIdle": null,
|
||||||
"SteamParentalPIN": "0",
|
"DismissInventoryNotifications": true,
|
||||||
"SteamApiKey": null,
|
"Enabled": false,
|
||||||
"SteamMasterID": 0,
|
"FarmingOrder": 0,
|
||||||
"SteamMasterClanID": 0,
|
"FarmOffline": false,
|
||||||
"CardDropsRestricted": true,
|
"GamesPlayedWhileIdle": [],
|
||||||
"DismissInventoryNotifications": true,
|
"HandleOfflineMessages": false,
|
||||||
"FarmingOrder": 0,
|
"IsBotAccount": false,
|
||||||
"FarmOffline": false,
|
"LootableTypes": [
|
||||||
"HandleOfflineMessages": false,
|
1,
|
||||||
"AcceptGifts": false,
|
5,
|
||||||
"IsBotAccount": false,
|
7
|
||||||
"ForwardKeysToOtherBots": false,
|
],
|
||||||
"DistributeKeys": false,
|
"PasswordFormat": 0,
|
||||||
"ShutdownOnFarmingFinished": false,
|
"Paused": false,
|
||||||
"SendOnFarmingFinished": false,
|
"RedeemingPreferences": 0,
|
||||||
"SteamTradeToken": null,
|
"SendOnFarmingFinished": false,
|
||||||
"SendTradePeriod": 0,
|
"SendTradePeriod": 0,
|
||||||
"TradingPreferences": 1,
|
"ShutdownOnFarmingFinished": false,
|
||||||
"AcceptConfirmationsPeriod": 0,
|
"SteamApiKey": null,
|
||||||
"CustomGamePlayedWhileFarming": null,
|
"SteamLogin": null,
|
||||||
"CustomGamePlayedWhileIdle": null,
|
"SteamMasterClanID": 0,
|
||||||
"GamesPlayedWhileIdle": []
|
"SteamMasterID": 0,
|
||||||
|
"SteamParentalPIN": "0",
|
||||||
|
"SteamPassword": null,
|
||||||
|
"SteamTradeToken": null,
|
||||||
|
"TradingPreferences": 1
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"Enabled": false,
|
"Enabled": false,
|
||||||
"SteamLogin": null,
|
"SteamLogin": null,
|
||||||
"SteamPassword": null
|
"SteamPassword": null
|
||||||
}
|
}
|
||||||
@@ -28,6 +28,7 @@ using System.ComponentModel;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Drawing.Design;
|
using System.Drawing.Design;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using ConfigGenerator.JSON;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace ConfigGenerator {
|
namespace ConfigGenerator {
|
||||||
@@ -56,9 +57,6 @@ namespace ConfigGenerator {
|
|||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public bool DismissInventoryNotifications { get; set; } = true;
|
public bool DismissInventoryNotifications { get; set; } = true;
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
|
||||||
public bool DistributeKeys { get; set; } = false;
|
|
||||||
|
|
||||||
[Category("\t\tCore")]
|
[Category("\t\tCore")]
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public bool Enabled { get; set; } = false;
|
public bool Enabled { get; set; } = false;
|
||||||
@@ -69,9 +67,6 @@ namespace ConfigGenerator {
|
|||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public bool FarmOffline { get; set; } = false;
|
public bool FarmOffline { get; set; } = false;
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
|
||||||
public bool ForwardKeysToOtherBots { get; set; } = false;
|
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public List<uint> GamesPlayedWhileIdle { get; set; } = new List<uint>();
|
public List<uint> GamesPlayedWhileIdle { get; set; } = new List<uint>();
|
||||||
|
|
||||||
@@ -83,6 +78,9 @@ namespace ConfigGenerator {
|
|||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public bool IsBotAccount { get; set; } = false;
|
public bool IsBotAccount { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty(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")]
|
[Category("\tAccess")]
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public ECryptoMethod PasswordFormat { get; set; } = ECryptoMethod.PlainText;
|
public ECryptoMethod PasswordFormat { get; set; } = ECryptoMethod.PlainText;
|
||||||
@@ -91,6 +89,11 @@ namespace ConfigGenerator {
|
|||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public bool Paused { get; set; } = false;
|
public bool Paused { get; set; } = false;
|
||||||
|
|
||||||
|
[Category("\tAdvanced")]
|
||||||
|
[Editor(typeof(FlagEnumUiEditor), typeof(UITypeEditor))]
|
||||||
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
|
public ERedeemingPreferences RedeemingPreferences { get; set; } = ERedeemingPreferences.None;
|
||||||
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public bool SendOnFarmingFinished { get; set; } = false;
|
public bool SendOnFarmingFinished { get; set; } = false;
|
||||||
|
|
||||||
@@ -191,6 +194,13 @@ namespace ConfigGenerator {
|
|||||||
NamesDescending
|
NamesDescending
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum ERedeemingPreferences : byte {
|
||||||
|
None = 0,
|
||||||
|
Forwarding = 1,
|
||||||
|
Distributing = 2
|
||||||
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
internal enum ETradingPreferences : byte {
|
internal enum ETradingPreferences : byte {
|
||||||
None = 0,
|
None = 0,
|
||||||
|
|||||||
@@ -73,6 +73,7 @@
|
|||||||
<Compile Include="ConfigPage.cs">
|
<Compile Include="ConfigPage.cs">
|
||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="JSON\Steam.cs" />
|
||||||
<Compile Include="Logging.cs" />
|
<Compile Include="Logging.cs" />
|
||||||
<Compile Include="MainForm.cs">
|
<Compile Include="MainForm.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace ConfigGenerator {
|
|||||||
private const ushort DefaultWCFPort = 1242;
|
private const ushort DefaultWCFPort = 1242;
|
||||||
|
|
||||||
// This is hardcoded blacklist which should not be possible to change
|
// This is hardcoded blacklist which should not be possible to change
|
||||||
private static readonly HashSet<uint> GlobalBlacklist = new HashSet<uint> { 267420, 303700, 335590, 368020, 425280, 480730 };
|
private static readonly HashSet<uint> GlobalBlacklist = new HashSet<uint> { 267420, 303700, 335590, 368020, 425280, 480730, 566020 };
|
||||||
|
|
||||||
[Category("\tUpdates")]
|
[Category("\tUpdates")]
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
@@ -64,10 +64,6 @@ namespace ConfigGenerator {
|
|||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public byte FarmingDelay { get; set; } = DefaultFarmingDelay;
|
public byte FarmingDelay { get; set; } = DefaultFarmingDelay;
|
||||||
|
|
||||||
[Category("\tDebugging")]
|
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
|
||||||
public bool ForceHttp { get; set; } = false;
|
|
||||||
|
|
||||||
[Category("\tPerformance")]
|
[Category("\tPerformance")]
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
public byte GiftsLimiterDelay { get; set; } = 1;
|
public byte GiftsLimiterDelay { get; set; } = 1;
|
||||||
@@ -116,7 +112,7 @@ namespace ConfigGenerator {
|
|||||||
|
|
||||||
[Category("\tAccess")]
|
[Category("\tAccess")]
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
public string WCFHostname { get; set; } = "localhost";
|
public string WCFHost { get; set; } = "127.0.0.1";
|
||||||
|
|
||||||
[Category("\tAccess")]
|
[Category("\tAccess")]
|
||||||
[JsonProperty(Required = Required.DisallowNull)]
|
[JsonProperty(Required = Required.DisallowNull)]
|
||||||
|
|||||||
44
ConfigGenerator/JSON/Steam.cs
Normal file
44
ConfigGenerator/JSON/Steam.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
_ _ _ ____ _ _____
|
||||||
|
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||||
|
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||||
|
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||||
|
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||||
|
|
||||||
|
Copyright 2015-2016 Łukasz "JustArchi" Domeradzki
|
||||||
|
Contact: JustArchi@JustArchi.net
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace ConfigGenerator.JSON {
|
||||||
|
internal static class Steam {
|
||||||
|
internal static class Item {
|
||||||
|
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||||
|
internal enum EType : byte {
|
||||||
|
Unknown,
|
||||||
|
BoosterPack,
|
||||||
|
Coupon,
|
||||||
|
Emoticon,
|
||||||
|
Gift,
|
||||||
|
FoilTradingCard,
|
||||||
|
ProfileBackground,
|
||||||
|
TradingCard,
|
||||||
|
SteamGems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,12 +31,18 @@ namespace GUI {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback.AvatarHash != null) {
|
if ((callback.AvatarHash == null) || (callback.AvatarHash.Length == 0)) {
|
||||||
string avatarHash = BitConverter.ToString(callback.AvatarHash).Replace("-", "").ToLowerInvariant();
|
return;
|
||||||
string avatarURL = "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/" + avatarHash.Substring(0, 2) + "/" + avatarHash + "_full.jpg";
|
|
||||||
AvatarPictureBox.ImageLocation = avatarURL;
|
|
||||||
AvatarPictureBox.LoadAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string avatarHash = BitConverter.ToString(callback.AvatarHash).Replace("-", "").ToLowerInvariant();
|
||||||
|
if (string.IsNullOrEmpty(avatarHash)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string avatarURL = "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/" + avatarHash.Substring(0, 2) + "/" + avatarHash + "_full.jpg";
|
||||||
|
AvatarPictureBox.ImageLocation = avatarURL;
|
||||||
|
AvatarPictureBox.LoadAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AvatarPictureBox_LoadCompleted(object sender, AsyncCompletedEventArgs e) {
|
private void AvatarPictureBox_LoadCompleted(object sender, AsyncCompletedEventArgs e) {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
internal static void OnPersonaState(Bot bot, SteamFriends.PersonaStateCallback callback) {
|
internal static void OnPersonaState(Bot bot, SteamFriends.PersonaStateCallback callback) {
|
||||||
if (bot == null) {
|
if (bot == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(bot));
|
Program.ArchiLogger.LogNullError(nameof(bot));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,9 @@
|
|||||||
<Compile Include="..\ArchiSteamFarm\CardsFarmer.cs">
|
<Compile Include="..\ArchiSteamFarm\CardsFarmer.cs">
|
||||||
<Link>CardsFarmer.cs</Link>
|
<Link>CardsFarmer.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\ArchiSteamFarm\CMsgs\CMsgClientClanInviteAction.cs">
|
||||||
|
<Link>CMsgs\CMsgClientClanInviteAction.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\ArchiSteamFarm\ConcurrentEnumerator.cs">
|
<Compile Include="..\ArchiSteamFarm\ConcurrentEnumerator.cs">
|
||||||
<Link>ConcurrentEnumerator.cs</Link>
|
<Link>ConcurrentEnumerator.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -148,6 +151,9 @@
|
|||||||
<Compile Include="..\ArchiSteamFarm\Statistics.cs">
|
<Compile Include="..\ArchiSteamFarm\Statistics.cs">
|
||||||
<Link>Statistics.cs</Link>
|
<Link>Statistics.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\ArchiSteamFarm\SteamSaleEvent.cs">
|
||||||
|
<Link>SteamSaleEvent.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\ArchiSteamFarm\Trading.cs">
|
<Compile Include="..\ArchiSteamFarm\Trading.cs">
|
||||||
<Link>Trading.cs</Link>
|
<Link>Trading.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace GUI {
|
|||||||
|
|
||||||
internal static void UpdateBotAvatar(string botName, Image image) {
|
internal static void UpdateBotAvatar(string botName, Image image) {
|
||||||
if (string.IsNullOrEmpty(botName) || (image == null)) {
|
if (string.IsNullOrEmpty(botName) || (image == null)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(botName) + " || " + nameof(image));
|
Program.ArchiLogger.LogNullError(nameof(botName) + " || " + nameof(image));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,17 +68,17 @@ namespace GUI {
|
|||||||
BotListView.LargeImageList = BotListView.SmallImageList = AvatarImageList;
|
BotListView.LargeImageList = BotListView.SmallImageList = AvatarImageList;
|
||||||
|
|
||||||
await Task.Run(async () => {
|
await Task.Run(async () => {
|
||||||
ASF.ArchiLogger.LogGenericInfo("ASF V" + SharedInfo.Version);
|
Program.ArchiLogger.LogGenericInfo("ASF V" + SharedInfo.Version);
|
||||||
|
|
||||||
if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
|
if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
|
||||||
ASF.ArchiLogger.LogGenericError("Config directory could not be found!");
|
Program.ArchiLogger.LogGenericError("Config directory could not be found!");
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
await ASF.CheckForUpdate().ConfigureAwait(false);
|
await ASF.CheckForUpdate().ConfigureAwait(false);
|
||||||
|
|
||||||
// Before attempting to connect, initialize our list of CMs
|
// Before attempting to connect, initialize our list of CMs
|
||||||
Bot.InitializeCMs(Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider);
|
await Bot.InitializeCMs(Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider).ConfigureAwait(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach (string botName in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*.json").Select(Path.GetFileNameWithoutExtension)) {
|
foreach (string botName in Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*.json").Select(Path.GetFileNameWithoutExtension)) {
|
||||||
@@ -133,7 +133,7 @@ namespace GUI {
|
|||||||
|
|
||||||
private static Bitmap ResizeImage(Image image, int width, int height) {
|
private static Bitmap ResizeImage(Image image, int width, int height) {
|
||||||
if ((image == null) || (width <= 0) || (height <= 0)) {
|
if ((image == null) || (width <= 0) || (height <= 0)) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(image) + " || " + nameof(width) + " || " + nameof(height));
|
Program.ArchiLogger.LogNullError(nameof(image) + " || " + nameof(width) + " || " + nameof(height));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ using SteamKit2;
|
|||||||
|
|
||||||
namespace ArchiSteamFarm {
|
namespace ArchiSteamFarm {
|
||||||
internal static class Program {
|
internal static class Program {
|
||||||
|
internal static readonly ArchiLogger ArchiLogger = new ArchiLogger(SharedInfo.ASF);
|
||||||
|
|
||||||
internal static GlobalConfig GlobalConfig { get; private set; }
|
internal static GlobalConfig GlobalConfig { get; private set; }
|
||||||
internal static GlobalDatabase GlobalDatabase { get; private set; }
|
internal static GlobalDatabase GlobalDatabase { get; private set; }
|
||||||
internal static WebBrowser WebBrowser { get; private set; }
|
internal static WebBrowser WebBrowser { get; private set; }
|
||||||
@@ -38,7 +40,7 @@ namespace ArchiSteamFarm {
|
|||||||
try {
|
try {
|
||||||
Process.Start(Assembly.GetEntryAssembly().Location, string.Join(" ", Environment.GetCommandLineArgs().Skip(1)));
|
Process.Start(Assembly.GetEntryAssembly().Location, string.Join(" ", Environment.GetCommandLineArgs().Skip(1)));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ASF.ArchiLogger.LogGenericException(e);
|
ArchiLogger.LogGenericException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
@@ -51,7 +53,7 @@ namespace ArchiSteamFarm {
|
|||||||
Logging.InitCoreLoggers();
|
Logging.InitCoreLoggers();
|
||||||
|
|
||||||
if (!Runtime.IsRuntimeSupported) {
|
if (!Runtime.IsRuntimeSupported) {
|
||||||
ASF.ArchiLogger.LogGenericError("ASF detected unsupported runtime version, program might NOT run correctly in current environment. You're running it at your own risk!");
|
ArchiLogger.LogGenericError("ASF detected unsupported runtime version, program might NOT run correctly in current environment. You're running it at your own risk!");
|
||||||
}
|
}
|
||||||
|
|
||||||
string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||||
@@ -101,7 +103,7 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
GlobalConfig = GlobalConfig.Load(globalConfigFile);
|
GlobalConfig = GlobalConfig.Load(globalConfigFile);
|
||||||
if (GlobalConfig == null) {
|
if (GlobalConfig == null) {
|
||||||
ASF.ArchiLogger.LogGenericError("Global config could not be loaded, please make sure that " + globalConfigFile + " exists and is valid!");
|
ArchiLogger.LogGenericError("Global config could not be loaded, please make sure that " + globalConfigFile + " exists and is valid!");
|
||||||
Exit(1);
|
Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,14 +111,14 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
GlobalDatabase = GlobalDatabase.Load(globalDatabaseFile);
|
GlobalDatabase = GlobalDatabase.Load(globalDatabaseFile);
|
||||||
if (GlobalDatabase == null) {
|
if (GlobalDatabase == null) {
|
||||||
ASF.ArchiLogger.LogGenericError("Global database could not be loaded, if issue persists, please remove " + globalDatabaseFile + " in order to recreate database!");
|
ArchiLogger.LogGenericError("Global database could not be loaded, if issue persists, please remove " + globalDatabaseFile + " in order to recreate database!");
|
||||||
Exit(1);
|
Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArchiWebHandler.Init();
|
ArchiWebHandler.Init();
|
||||||
WebBrowser.Init();
|
WebBrowser.Init();
|
||||||
|
|
||||||
WebBrowser = new WebBrowser(ASF.ArchiLogger);
|
WebBrowser = new WebBrowser(ArchiLogger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -132,20 +134,20 @@ namespace ArchiSteamFarm {
|
|||||||
|
|
||||||
private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) {
|
private static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args) {
|
||||||
if (args?.ExceptionObject == null) {
|
if (args?.ExceptionObject == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(args) + " || " + nameof(args.ExceptionObject));
|
ArchiLogger.LogNullError(nameof(args) + " || " + nameof(args.ExceptionObject));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogFatalException((Exception) args.ExceptionObject);
|
ArchiLogger.LogFatalException((Exception) args.ExceptionObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) {
|
private static void UnobservedTaskExceptionHandler(object sender, UnobservedTaskExceptionEventArgs args) {
|
||||||
if (args?.Exception == null) {
|
if (args?.Exception == null) {
|
||||||
ASF.ArchiLogger.LogNullError(nameof(args) + " || " + nameof(args.Exception));
|
ArchiLogger.LogNullError(nameof(args) + " || " + nameof(args.Exception));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASF.ArchiLogger.LogFatalException(args.Exception);
|
ArchiLogger.LogFatalException(args.Exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user