mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-27 19:50:47 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
134aa62952 | ||
|
|
5a4132a679 | ||
|
|
edb047980e | ||
|
|
7d32adac13 | ||
|
|
95637ea3a7 | ||
|
|
02a547e7d2 | ||
|
|
9594357d56 | ||
|
|
ce166baab6 | ||
|
|
1ec0b20604 | ||
|
|
26bd76cc4a | ||
|
|
8e1d02f43f | ||
|
|
b802822699 | ||
|
|
be77e8d380 | ||
|
|
000b902ced | ||
|
|
d09be453f3 | ||
|
|
5f1342ae26 | ||
|
|
00b4c28843 | ||
|
|
cb6cfd08c2 | ||
|
|
f53911bd9a | ||
|
|
527641439b | ||
|
|
647a0ee865 | ||
|
|
b9f2dd1292 | ||
|
|
e675a3a488 | ||
|
|
fb8692d28c | ||
|
|
cf4141dde7 | ||
|
|
963f56ccf2 | ||
|
|
c754a18603 | ||
|
|
eb886e8ca8 | ||
|
|
e8889fb087 | ||
|
|
d627a5ee9d | ||
|
|
35bd36bbd9 | ||
|
|
d79944085f | ||
|
|
4e191367da | ||
|
|
f88bfe9f83 | ||
|
|
86aa9e781d | ||
|
|
6ae7e74daf |
@@ -8,6 +8,10 @@ mono:
|
||||
- weekly
|
||||
- latest
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- mono: weekly
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
webhooks:
|
||||
|
||||
@@ -11,6 +11,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConfigGenerator", "ConfigGe
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GUI", "GUI\GUI.csproj", "{13949B41-787C-4558-90AE-A9F9E7F86B1F}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{35AF7887-08B9-40E8-A5EA-797D8B60B30C} = {35AF7887-08B9-40E8-A5EA-797D8B60B30C}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -166,8 +166,8 @@ namespace ArchiSteamFarm {
|
||||
internal void OnDisconnected() => Ready = false;
|
||||
|
||||
internal async Task<bool> Init(ulong steamID, EUniverse universe, string webAPIUserNonce, string parentalPin) {
|
||||
if ((steamID == 0) || (universe == EUniverse.Invalid) || string.IsNullOrEmpty(webAPIUserNonce)) {
|
||||
Logging.LogNullError(nameof(steamID) + " || " + nameof(universe) + " || " + nameof(webAPIUserNonce), Bot.BotName);
|
||||
if ((steamID == 0) || (universe == EUniverse.Invalid) || string.IsNullOrEmpty(webAPIUserNonce) || string.IsNullOrEmpty(parentalPin)) {
|
||||
Logging.LogNullError(nameof(steamID) + " || " + nameof(universe) + " || " + nameof(webAPIUserNonce) + " || " + nameof(parentalPin), Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -217,19 +217,29 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Success!", Bot.BotName);
|
||||
|
||||
WebBrowser.CookieContainer.Add(new Cookie("sessionid", sessionID, "/", "." + SteamCommunityHost));
|
||||
|
||||
string steamLogin = authResult["token"].Value;
|
||||
WebBrowser.CookieContainer.Add(new Cookie("steamLogin", steamLogin, "/", "." + SteamCommunityHost));
|
||||
if (string.IsNullOrEmpty(steamLogin)) {
|
||||
Logging.LogNullError(nameof(steamLogin), Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
string steamLoginSecure = authResult["tokensecure"].Value;
|
||||
if (string.IsNullOrEmpty(steamLoginSecure)) {
|
||||
Logging.LogNullError(nameof(steamLoginSecure), Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
WebBrowser.CookieContainer.Add(new Cookie("sessionid", sessionID, "/", "." + SteamCommunityHost));
|
||||
WebBrowser.CookieContainer.Add(new Cookie("steamLogin", steamLogin, "/", "." + SteamCommunityHost));
|
||||
WebBrowser.CookieContainer.Add(new Cookie("steamLoginSecure", steamLoginSecure, "/", "." + SteamCommunityHost));
|
||||
|
||||
Logging.LogGenericInfo("Success!", Bot.BotName);
|
||||
|
||||
// Unlock Steam Parental if needed
|
||||
if (!await UnlockParentalAccount(parentalPin).ConfigureAwait(false)) {
|
||||
return false;
|
||||
if (!parentalPin.Equals("0")) {
|
||||
if (!await UnlockParentalAccount(parentalPin).ConfigureAwait(false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Ready = true;
|
||||
@@ -377,11 +387,6 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
if (response != null) {
|
||||
// TODO: Remove me
|
||||
if (!response.Success) {
|
||||
Logging.LogGenericError("HandleConfirmations() debug content: " + json, Bot.BotName);
|
||||
}
|
||||
|
||||
return response.Success;
|
||||
}
|
||||
|
||||
@@ -657,37 +662,38 @@ namespace ArchiSteamFarm {
|
||||
return result;
|
||||
}
|
||||
|
||||
internal async Task<bool> AcceptTradeOffer(ulong tradeID) {
|
||||
internal async Task AcceptTradeOffer(ulong tradeID) {
|
||||
if (tradeID == 0) {
|
||||
Logging.LogNullError(nameof(tradeID), Bot.BotName);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
string sessionID = WebBrowser.CookieContainer.GetCookieValue(SteamCommunityURL, "sessionid");
|
||||
if (string.IsNullOrEmpty(sessionID)) {
|
||||
Logging.LogNullError(nameof(sessionID), Bot.BotName);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
string referer = SteamCommunityURL + "/tradeoffer/" + tradeID;
|
||||
string request = referer + "/accept";
|
||||
|
||||
Dictionary<string, string> data = new Dictionary<string, string>(3) {
|
||||
{ "sessionid", sessionID },
|
||||
{ "serverid", "1" },
|
||||
{ "tradeofferid", tradeID.ToString() }
|
||||
};
|
||||
|
||||
return await WebBrowser.UrlPostRetry(request, data, referer).ConfigureAwait(false);
|
||||
await WebBrowser.UrlPostRetry(request, data, referer).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal bool DeclineTradeOffer(ulong tradeID) {
|
||||
internal void DeclineTradeOffer(ulong tradeID) {
|
||||
if ((tradeID == 0) || string.IsNullOrEmpty(Bot.BotConfig.SteamApiKey)) {
|
||||
Logging.LogNullError(nameof(tradeID) + " || " + nameof(Bot.BotConfig.SteamApiKey), Bot.BotName);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
KeyValue response = null;
|
||||
@@ -707,12 +713,9 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
if (response != null) {
|
||||
return true;
|
||||
if (response == null) {
|
||||
Logging.LogGenericWarning("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
}
|
||||
|
||||
Logging.LogGenericWarning("Request failed even after " + WebBrowser.MaxRetries + " tries", Bot.BotName);
|
||||
return false;
|
||||
}
|
||||
|
||||
internal async Task<HashSet<Steam.Item>> GetMySteamInventory(bool tradable) {
|
||||
@@ -960,10 +963,6 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parentalPin.Equals("0")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Unlocking parental account...", Bot.BotName);
|
||||
|
||||
string request = SteamCommunityURL + "/parental/ajaxunlock";
|
||||
|
||||
@@ -40,7 +40,6 @@ using SteamKit2.Discovery;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class Bot : IDisposable {
|
||||
private const ulong ArchiSCFarmGroup = 103582791440160998;
|
||||
private const ushort CallbackSleep = 500; // In miliseconds
|
||||
private const ushort MaxSteamMessageLength = 2048;
|
||||
|
||||
@@ -68,7 +67,7 @@ namespace ArchiSteamFarm {
|
||||
private readonly SteamApps SteamApps;
|
||||
private readonly SteamFriends SteamFriends;
|
||||
private readonly SteamUser SteamUser;
|
||||
private readonly Timer AcceptConfirmationsTimer, SendItemsTimer;
|
||||
private readonly Timer AcceptConfirmationsTimer, HeartBeatTimer, SendItemsTimer;
|
||||
private readonly Trading Trading;
|
||||
|
||||
[JsonProperty]
|
||||
@@ -104,7 +103,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private static bool IsOwner(ulong steamID) {
|
||||
if (steamID != 0) {
|
||||
return steamID == Program.GlobalConfig.SteamOwnerID;
|
||||
return (steamID == Program.GlobalConfig.SteamOwnerID) || (Debugging.IsDebugBuild && (steamID == SharedInfo.ArchiSteamID));
|
||||
}
|
||||
|
||||
Logging.LogNullError(nameof(steamID));
|
||||
@@ -230,16 +229,23 @@ namespace ArchiSteamFarm {
|
||||
CardsFarmer = new CardsFarmer(this);
|
||||
Trading = new Trading(this);
|
||||
|
||||
if ((AcceptConfirmationsTimer == null) && (BotConfig.AcceptConfirmationsPeriod > 0)) {
|
||||
HeartBeatTimer = new Timer(
|
||||
async e => await HeartBeat().ConfigureAwait(false),
|
||||
null,
|
||||
TimeSpan.FromMinutes(1) + TimeSpan.FromMinutes(0.2 * Bots.Count), // Delay
|
||||
TimeSpan.FromMinutes(1) // Period
|
||||
);
|
||||
|
||||
if (BotConfig.AcceptConfirmationsPeriod > 0) {
|
||||
AcceptConfirmationsTimer = new Timer(
|
||||
async e => await AcceptConfirmations(true).ConfigureAwait(false),
|
||||
null,
|
||||
TimeSpan.FromMinutes(BotConfig.AcceptConfirmationsPeriod) + TimeSpan.FromMinutes(Bots.Count), // Delay
|
||||
TimeSpan.FromMinutes(BotConfig.AcceptConfirmationsPeriod) + TimeSpan.FromMinutes(0.2 * Bots.Count), // Delay
|
||||
TimeSpan.FromMinutes(BotConfig.AcceptConfirmationsPeriod) // Period
|
||||
);
|
||||
}
|
||||
|
||||
if ((SendItemsTimer == null) && (BotConfig.SendTradePeriod > 0)) {
|
||||
if ((BotConfig.SendTradePeriod > 0) && (BotConfig.SteamMasterID != 0)) {
|
||||
SendItemsTimer = new Timer(
|
||||
async e => await ResponseLoot(BotConfig.SteamMasterID).ConfigureAwait(false),
|
||||
null,
|
||||
@@ -260,15 +266,17 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
GiftsSemaphore.Dispose();
|
||||
LoginSemaphore.Dispose();
|
||||
// Those are objects that are always being created if constructor doesn't throw exception
|
||||
ArchiWebHandler.Dispose();
|
||||
CardsFarmer.Dispose();
|
||||
HeartBeatTimer.Dispose();
|
||||
HandledGifts.Dispose();
|
||||
OwnedPackageIDs.Dispose();
|
||||
Trading.Dispose();
|
||||
|
||||
// Those are objects that might be null and the check should be in-place
|
||||
AcceptConfirmationsTimer?.Dispose();
|
||||
ArchiWebHandler?.Dispose();
|
||||
CardsFarmer?.Dispose();
|
||||
SendItemsTimer?.Dispose();
|
||||
Trading?.Dispose();
|
||||
}
|
||||
|
||||
internal async Task<bool> AcceptConfirmations(bool accept, Steam.ConfirmationDetails.EType acceptedType = Steam.ConfirmationDetails.EType.Unknown, ulong acceptedSteamID = 0, HashSet<ulong> acceptedTradeIDs = null) {
|
||||
@@ -323,12 +331,12 @@ namespace ArchiSteamFarm {
|
||||
callback = await SteamUser.RequestWebAPIUserNonce();
|
||||
} catch (Exception e) {
|
||||
Logging.LogGenericException(e, BotName);
|
||||
Start().Forget();
|
||||
await Start().ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(callback?.Nonce)) {
|
||||
Start().Forget();
|
||||
await Start().ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -336,7 +344,7 @@ namespace ArchiSteamFarm {
|
||||
return true;
|
||||
}
|
||||
|
||||
Start().Forget();
|
||||
await Start().ConfigureAwait(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -355,14 +363,22 @@ namespace ArchiSteamFarm {
|
||||
Events.OnBotShutdown();
|
||||
}
|
||||
|
||||
internal async Task LootIfNeeded() {
|
||||
if (!BotConfig.SendOnFarmingFinished || (BotConfig.SteamMasterID == 0) || !SteamClient.IsConnected || (BotConfig.SteamMasterID == SteamClient.SteamID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await ResponseLoot(BotConfig.SteamMasterID).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal void OnFarmingStopped() => ResetGamesPlayed();
|
||||
|
||||
internal async Task OnFarmingFinished(bool farmedSomething) {
|
||||
OnFarmingStopped();
|
||||
|
||||
if ((farmedSomething || !FirstTradeSent) && BotConfig.SendOnFarmingFinished) {
|
||||
if (farmedSomething || !FirstTradeSent) {
|
||||
FirstTradeSent = true;
|
||||
await ResponseLoot(BotConfig.SteamMasterID).ConfigureAwait(false);
|
||||
await LootIfNeeded().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (BotConfig.ShutdownOnFarmingFinished) {
|
||||
@@ -457,6 +473,8 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
return await ResponseOwns(steamID, BotName, args[1]).ConfigureAwait(false);
|
||||
case "!OWNSALL":
|
||||
return await ResponseOwnsAll(steamID, args[1]).ConfigureAwait(false);
|
||||
case "!PASSWORD":
|
||||
return ResponsePassword(steamID, args[1]);
|
||||
case "!PAUSE":
|
||||
@@ -486,18 +504,40 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HeartBeat() {
|
||||
if (!SteamClient.IsConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await SteamApps.PICSGetProductInfo(0, null);
|
||||
} catch {
|
||||
if (!SteamClient.IsConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
Logging.LogGenericWarning("Connection to Steam Network lost, reconnecting...", BotName);
|
||||
|
||||
Task.Run(async () => {
|
||||
await LimitLoginRequestsAsync().ConfigureAwait(false);
|
||||
|
||||
if (!SteamClient.IsConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
SteamClient.Connect();
|
||||
}).Forget();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Start() {
|
||||
if (!KeepRunning) {
|
||||
KeepRunning = true;
|
||||
Task.Run(() => HandleCallbacks()).Forget();
|
||||
Logging.LogGenericInfo("Starting...", BotName);
|
||||
}
|
||||
|
||||
// 2FA tokens are expiring soon, don't use limiter when user is providing one
|
||||
if ((TwoFactorCode == null) || (BotDatabase.MobileAuthenticator != null)) {
|
||||
await LimitLoginRequestsAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Starting...", BotName);
|
||||
await LimitLoginRequestsAsync().ConfigureAwait(false);
|
||||
SteamClient.Connect();
|
||||
}
|
||||
|
||||
@@ -647,6 +687,10 @@ namespace ArchiSteamFarm {
|
||||
return "Bot " + BotName + " is not running.";
|
||||
}
|
||||
|
||||
if (PlayingBlocked) {
|
||||
return "Bot " + BotName + " is currently being used.";
|
||||
}
|
||||
|
||||
if (CardsFarmer.ManualMode) {
|
||||
return "Bot " + BotName + " is running in manual mode.";
|
||||
}
|
||||
@@ -1176,7 +1220,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
if ((ownedGames == null) || (ownedGames.Count == 0)) {
|
||||
return "List of owned games is empty!";
|
||||
return "<" + BotName + "> List of owned games is empty!";
|
||||
}
|
||||
|
||||
StringBuilder response = new StringBuilder();
|
||||
@@ -1188,9 +1232,9 @@ namespace ArchiSteamFarm {
|
||||
if (uint.TryParse(game, out appID)) {
|
||||
string ownedName;
|
||||
if (ownedGames.TryGetValue(appID, out ownedName)) {
|
||||
response.Append(Environment.NewLine + "Owned already: " + appID + " | " + ownedName);
|
||||
response.Append(Environment.NewLine + "<" + BotName + "> Owned already: " + appID + " | " + ownedName);
|
||||
} else {
|
||||
response.Append(Environment.NewLine + "Not owned yet: " + appID);
|
||||
response.Append(Environment.NewLine + "<" + BotName + "> Not owned yet: " + appID);
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -1198,7 +1242,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
// This is a string, so check our entire library
|
||||
foreach (KeyValuePair<uint, string> ownedGame in ownedGames.Where(ownedGame => ownedGame.Value.IndexOf(game, StringComparison.OrdinalIgnoreCase) >= 0)) {
|
||||
response.Append(Environment.NewLine + "Owned already: " + ownedGame.Key + " | " + ownedGame.Value);
|
||||
response.Append(Environment.NewLine + "<" + BotName + "> Owned already: " + ownedGame.Key + " | " + ownedGame.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1206,7 +1250,7 @@ namespace ArchiSteamFarm {
|
||||
return response.ToString();
|
||||
}
|
||||
|
||||
return "Not owned yet: " + query;
|
||||
return "<" + BotName + "> Not owned yet: " + query;
|
||||
}
|
||||
|
||||
private static async Task<string> ResponseOwns(ulong steamID, string botName, string query) {
|
||||
@@ -1227,6 +1271,26 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static async Task<string> ResponseOwnsAll(ulong steamID, string query) {
|
||||
if ((steamID == 0) || string.IsNullOrEmpty(query)) {
|
||||
Logging.LogNullError(nameof(steamID) + " || " + nameof(query));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!IsOwner(steamID)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string[] responses = await Task.WhenAll(Bots.OrderBy(bot => bot.Key).Select(bot => bot.Value.ResponseOwns(steamID, query))).ConfigureAwait(false);
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
foreach (string response in responses.Where(response => !string.IsNullOrEmpty(response))) {
|
||||
result.Append(response);
|
||||
}
|
||||
|
||||
return result.Length != 0 ? result.ToString() : null;
|
||||
}
|
||||
|
||||
private async Task<string> ResponsePlay(ulong steamID, HashSet<uint> gameIDs) {
|
||||
if ((steamID == 0) || (gameIDs == null) || (gameIDs.Count == 0)) {
|
||||
Logging.LogNullError(nameof(steamID) + " || " + nameof(gameIDs) + " || " + nameof(gameIDs.Count), BotName);
|
||||
@@ -1604,6 +1668,10 @@ namespace ArchiSteamFarm {
|
||||
// 2FA tokens are expiring soon, don't use limiter when user is providing one
|
||||
if ((TwoFactorCode == null) || (BotDatabase.MobileAuthenticator != null)) {
|
||||
await LimitLoginRequestsAsync().ConfigureAwait(false);
|
||||
|
||||
if (!KeepRunning || SteamClient.IsConnected) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SteamClient.Connect();
|
||||
@@ -1888,7 +1956,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
if (Program.GlobalConfig.Statistics) {
|
||||
ArchiWebHandler.JoinGroup(ArchiSCFarmGroup).Forget();
|
||||
ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID).Forget();
|
||||
}
|
||||
|
||||
Trading.CheckTrades().Forget();
|
||||
@@ -1974,7 +2042,7 @@ namespace ArchiSteamFarm {
|
||||
foreach (ArchiHandler.NotificationsCallback.ENotification notification in callback.Notifications) {
|
||||
switch (notification) {
|
||||
case ArchiHandler.NotificationsCallback.ENotification.Items:
|
||||
CardsFarmer.OnNewItemsNotification();
|
||||
CardsFarmer.OnNewItemsNotification().Forget();
|
||||
if (BotConfig.DismissInventoryNotifications) {
|
||||
ArchiWebHandler.MarkInventory().Forget();
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace ArchiSteamFarm {
|
||||
internal readonly ulong SteamMasterClanID = 0;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
internal readonly bool CardDropsRestricted = false;
|
||||
internal readonly bool CardDropsRestricted = true;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
internal readonly bool DismissInventoryNotifications = true;
|
||||
|
||||
@@ -45,11 +45,11 @@ namespace ArchiSteamFarm {
|
||||
internal float HoursPlayed { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal byte CardsRemaining { get; set; }
|
||||
internal ushort CardsRemaining { get; set; }
|
||||
|
||||
internal string HeaderURL => "https://steamcdn-a.akamaihd.net/steam/apps/" + AppID + "/header.jpg";
|
||||
|
||||
internal Game(uint appID, string gameName, float hoursPlayed, byte cardsRemaining) {
|
||||
internal Game(uint appID, string gameName, float hoursPlayed, ushort cardsRemaining) {
|
||||
if ((appID == 0) || string.IsNullOrEmpty(gameName) || (hoursPlayed < 0) || (cardsRemaining == 0)) {
|
||||
throw new ArgumentOutOfRangeException(nameof(appID) + " || " + nameof(gameName) + " || " + nameof(hoursPlayed) + " || " + nameof(cardsRemaining));
|
||||
}
|
||||
@@ -88,7 +88,7 @@ namespace ArchiSteamFarm {
|
||||
private readonly ManualResetEventSlim FarmResetEvent = new ManualResetEventSlim(false);
|
||||
private readonly SemaphoreSlim FarmingSemaphore = new SemaphoreSlim(1);
|
||||
private readonly Bot Bot;
|
||||
private readonly Timer Timer;
|
||||
private readonly Timer IdleFarmingTimer;
|
||||
|
||||
[JsonProperty]
|
||||
internal bool ManualMode { get; private set; }
|
||||
@@ -102,22 +102,25 @@ namespace ArchiSteamFarm {
|
||||
|
||||
Bot = bot;
|
||||
|
||||
if ((Timer == null) && (Program.GlobalConfig.IdleFarmingPeriod > 0)) {
|
||||
Timer = new Timer(
|
||||
if (Program.GlobalConfig.IdleFarmingPeriod > 0) {
|
||||
IdleFarmingTimer = new Timer(
|
||||
e => CheckGamesForFarming(),
|
||||
null,
|
||||
TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) + TimeSpan.FromMinutes(Bot.Bots.Count), // Delay
|
||||
TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) + TimeSpan.FromMinutes(0.5 * Bot.Bots.Count), // Delay
|
||||
TimeSpan.FromHours(Program.GlobalConfig.IdleFarmingPeriod) // Period
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
// Those are objects that are always being created if constructor doesn't throw exception
|
||||
CurrentGamesFarming.Dispose();
|
||||
FarmResetEvent.Dispose();
|
||||
GamesToFarm.Dispose();
|
||||
FarmingSemaphore.Dispose();
|
||||
FarmResetEvent.Dispose();
|
||||
|
||||
Timer?.Dispose();
|
||||
// Those are objects that might be null and the check should be in-place
|
||||
IdleFarmingTimer?.Dispose();
|
||||
}
|
||||
|
||||
internal async Task SwitchToManualMode(bool manualMode) {
|
||||
@@ -245,12 +248,15 @@ namespace ArchiSteamFarm {
|
||||
|
||||
internal void OnDisconnected() => StopFarming().Forget();
|
||||
|
||||
internal void OnNewItemsNotification() {
|
||||
if (!NowFarming) {
|
||||
internal async Task OnNewItemsNotification() {
|
||||
if (NowFarming) {
|
||||
FarmResetEvent.Set();
|
||||
return;
|
||||
}
|
||||
|
||||
FarmResetEvent.Set();
|
||||
// If we're not farming, and we got new items, it's likely to be a booster pack or likewise
|
||||
// In this case, perform a loot if user wants to do so
|
||||
await Bot.LootIfNeeded().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal async Task OnNewGameAdded() {
|
||||
@@ -442,8 +448,8 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
byte cardsRemaining;
|
||||
if (!byte.TryParse(progressMatch.Value, out cardsRemaining) || (cardsRemaining == 0)) {
|
||||
ushort cardsRemaining;
|
||||
if (!ushort.TryParse(progressMatch.Value, out cardsRemaining) || (cardsRemaining == 0)) {
|
||||
Logging.LogNullError(nameof(cardsRemaining), Bot.BotName);
|
||||
return;
|
||||
}
|
||||
@@ -527,11 +533,11 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte cardsRemaining = 0;
|
||||
ushort cardsRemaining = 0;
|
||||
|
||||
Match match = Regex.Match(progress, @"\d+");
|
||||
if (match.Success) {
|
||||
if (!byte.TryParse(match.Value, out cardsRemaining)) {
|
||||
if (!ushort.TryParse(match.Value, out cardsRemaining)) {
|
||||
Logging.LogNullError(nameof(cardsRemaining), Bot.BotName);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -41,12 +41,11 @@ namespace ArchiSteamFarm {
|
||||
private static readonly ConcurrentHashSet<LoggingRule> ConsoleLoggingRules = new ConcurrentHashSet<LoggingRule>();
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private static bool IsUsingCustomConfiguration, IsWaitingForUserInput;
|
||||
private static bool IsWaitingForUserInput;
|
||||
|
||||
internal static void InitCoreLoggers() {
|
||||
internal static void InitLoggers() {
|
||||
if (LogManager.Configuration != null) {
|
||||
// User provided custom NLog config, or we have it set already, so don't override it
|
||||
IsUsingCustomConfiguration = true;
|
||||
InitConsoleLoggers();
|
||||
LogManager.ConfigurationChanged += OnConfigurationChanged;
|
||||
return;
|
||||
@@ -61,15 +60,6 @@ namespace ArchiSteamFarm {
|
||||
config.AddTarget(consoleTarget);
|
||||
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, consoleTarget));
|
||||
|
||||
LogManager.Configuration = config;
|
||||
InitConsoleLoggers();
|
||||
}
|
||||
|
||||
internal static void InitEnhancedLoggers() {
|
||||
if (IsUsingCustomConfiguration) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Program.IsRunningAsService) {
|
||||
EventLogTarget eventLogTarget = new EventLogTarget("EventLog") {
|
||||
Layout = EventLogLayout,
|
||||
@@ -77,21 +67,21 @@ namespace ArchiSteamFarm {
|
||||
Source = SharedInfo.EventLogSource
|
||||
};
|
||||
|
||||
LogManager.Configuration.AddTarget(eventLogTarget);
|
||||
LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, eventLogTarget));
|
||||
} else {
|
||||
config.AddTarget(eventLogTarget);
|
||||
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, eventLogTarget));
|
||||
} else if (Program.Mode != Program.EMode.Client) {
|
||||
FileTarget fileTarget = new FileTarget("File") {
|
||||
DeleteOldFileOnStartup = true,
|
||||
FileName = SharedInfo.LogFile,
|
||||
Layout = GeneralLayout
|
||||
};
|
||||
|
||||
LogManager.Configuration.AddTarget(fileTarget);
|
||||
LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, fileTarget));
|
||||
config.AddTarget(fileTarget);
|
||||
config.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, fileTarget));
|
||||
}
|
||||
|
||||
LogManager.ReconfigExistingLoggers();
|
||||
LogGenericInfo("Logging module initialized!");
|
||||
LogManager.Configuration = config;
|
||||
InitConsoleLoggers();
|
||||
}
|
||||
|
||||
internal static void OnUserInputStart() {
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -35,9 +34,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal static class Program {
|
||||
private enum EMode : byte {
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
||||
Unknown,
|
||||
internal enum EMode : byte {
|
||||
Normal, // Standard most common usage
|
||||
Client, // WCF client only
|
||||
Server // Normal + WCF server
|
||||
@@ -50,12 +47,11 @@ namespace ArchiSteamFarm {
|
||||
|
||||
internal static bool IsRunningAsService { get; private set; }
|
||||
internal static bool ShutdownSequenceInitialized { get; private set; }
|
||||
internal static EMode Mode { get; private set; } = EMode.Normal;
|
||||
internal static GlobalConfig GlobalConfig { get; private set; }
|
||||
internal static GlobalDatabase GlobalDatabase { get; private set; }
|
||||
internal static WebBrowser WebBrowser { get; private set; }
|
||||
|
||||
private static EMode Mode = EMode.Normal;
|
||||
|
||||
internal static void Exit(byte exitCode = 0) {
|
||||
Shutdown();
|
||||
Environment.Exit(exitCode);
|
||||
@@ -194,6 +190,12 @@ namespace ArchiSteamFarm {
|
||||
switch (arg) {
|
||||
case "":
|
||||
break;
|
||||
case "--client":
|
||||
Mode = EMode.Client;
|
||||
break;
|
||||
case "--server":
|
||||
Mode = EMode.Server;
|
||||
break;
|
||||
default:
|
||||
if (arg.StartsWith("--", StringComparison.Ordinal)) {
|
||||
if (arg.StartsWith("--path=", StringComparison.Ordinal) && (arg.Length > 7)) {
|
||||
@@ -266,14 +268,6 @@ namespace ArchiSteamFarm {
|
||||
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
|
||||
TaskScheduler.UnobservedTaskException += UnobservedTaskExceptionHandler;
|
||||
|
||||
Logging.InitCoreLoggers();
|
||||
Logging.LogGenericInfo("ASF V" + SharedInfo.Version);
|
||||
|
||||
if (!Runtime.IsRuntimeSupported) {
|
||||
Logging.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);
|
||||
}
|
||||
|
||||
string homeDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
if (!string.IsNullOrEmpty(homeDirectory)) {
|
||||
Directory.SetCurrentDirectory(homeDirectory);
|
||||
@@ -301,6 +295,14 @@ namespace ArchiSteamFarm {
|
||||
ParsePreInitArgs(args);
|
||||
}
|
||||
|
||||
Logging.InitLoggers();
|
||||
Logging.LogGenericInfo("ASF V" + SharedInfo.Version);
|
||||
|
||||
if (!Runtime.IsRuntimeSupported) {
|
||||
Logging.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);
|
||||
}
|
||||
|
||||
InitServices();
|
||||
|
||||
// If debugging is on, we prepare debug directory prior to running
|
||||
@@ -326,8 +328,6 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// From now on it's server mode
|
||||
Logging.InitEnhancedLoggers();
|
||||
|
||||
if (!Directory.Exists(SharedInfo.ConfigDirectory)) {
|
||||
Logging.LogGenericError("Config directory doesn't exist!");
|
||||
Thread.Sleep(5000);
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
Version minNetVersion = new Version(4, 6);
|
||||
Version minNetVersion = new Version(4, 6, 1);
|
||||
|
||||
if (netVersion >= minNetVersion) {
|
||||
Logging.LogGenericInfo("Your .NET version is OK. Required: " + minNetVersion + " | Found: " + netVersion);
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace ArchiSteamFarm {
|
||||
WCFHostname
|
||||
}
|
||||
|
||||
internal const string VersionNumber = "2.1.3.8";
|
||||
internal const string VersionNumber = "2.1.4.2";
|
||||
internal const string Copyright = "Copyright © ArchiSteamFarm 2015-2016";
|
||||
|
||||
internal const string GithubRepo = "JustArchi/ArchiSteamFarm";
|
||||
@@ -58,6 +58,9 @@ namespace ArchiSteamFarm {
|
||||
internal const string DebugDirectory = "debug";
|
||||
internal const string LogFile = "log.txt";
|
||||
|
||||
internal const ulong ArchiSteamID = 76561198006963719;
|
||||
internal const ulong ASFGroupSteamID = 103582791440160998;
|
||||
|
||||
internal const string GithubReleaseURL = "https://api.github.com/repos/" + GithubRepo + "/releases"; // GitHub API is HTTPS only
|
||||
internal const string GlobalConfigFileName = ASF + ".json";
|
||||
internal const string GlobalDatabaseFileName = ASF + ".db";
|
||||
|
||||
@@ -129,6 +129,11 @@ namespace ArchiSteamFarm {
|
||||
await Task.Delay(1000).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, acceptedTradeIDs).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (results.Any(result => (result != null) && ((result.Result == ParseTradeResult.EResult.AcceptedWithItemLose) || (result.Result == ParseTradeResult.EResult.AcceptedWithoutItemLose)))) {
|
||||
// If we finished a trade, perform a loot if user wants to do so
|
||||
await Bot.LootIfNeeded().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ParseTradeResult> ParseTrade(Steam.TradeOffer tradeOffer) {
|
||||
@@ -152,23 +157,25 @@ namespace ArchiSteamFarm {
|
||||
case ParseTradeResult.EResult.AcceptedWithItemLose:
|
||||
case ParseTradeResult.EResult.AcceptedWithoutItemLose:
|
||||
Logging.LogGenericInfo("Accepting trade: " + tradeOffer.TradeOfferID, Bot.BotName);
|
||||
return await Bot.ArchiWebHandler.AcceptTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false) ? result : null;
|
||||
await Bot.ArchiWebHandler.AcceptTradeOffer(tradeOffer.TradeOfferID).ConfigureAwait(false);
|
||||
break;
|
||||
case ParseTradeResult.EResult.RejectedPermanently:
|
||||
case ParseTradeResult.EResult.RejectedTemporarily:
|
||||
if (result.Result == ParseTradeResult.EResult.RejectedPermanently) {
|
||||
if (Bot.BotConfig.IsBotAccount) {
|
||||
Logging.LogGenericInfo("Rejecting trade: " + tradeOffer.TradeOfferID, Bot.BotName);
|
||||
return Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID) ? result : null;
|
||||
Bot.ArchiWebHandler.DeclineTradeOffer(tradeOffer.TradeOfferID);
|
||||
break;
|
||||
}
|
||||
|
||||
IgnoredTrades.Add(tradeOffer.TradeOfferID);
|
||||
}
|
||||
|
||||
Logging.LogGenericInfo("Ignoring trade: " + tradeOffer.TradeOfferID, Bot.BotName);
|
||||
return result;
|
||||
default:
|
||||
return result;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<ParseTradeResult> ShouldAcceptTrade(Steam.TradeOffer tradeOffer) {
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace ArchiSteamFarm {
|
||||
public string GetStatus() => Program.GlobalConfig.SteamOwnerID == 0 ? "{}" : Bot.GetAPIStatus();
|
||||
|
||||
public void Dispose() {
|
||||
Client?.Close();
|
||||
StopClient();
|
||||
StopServer();
|
||||
}
|
||||
|
||||
@@ -141,6 +141,18 @@ namespace ArchiSteamFarm {
|
||||
|
||||
return Client.HandleCommand(input);
|
||||
}
|
||||
|
||||
private void StopClient() {
|
||||
if (Client == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Client.State != CommunicationState.Closed) {
|
||||
Client.Close();
|
||||
}
|
||||
|
||||
Client = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class Client : ClientBase<IWCF> {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"SteamApiKey": null,
|
||||
"SteamMasterID": 0,
|
||||
"SteamMasterClanID": 0,
|
||||
"CardDropsRestricted": false,
|
||||
"CardDropsRestricted": true,
|
||||
"DismissInventoryNotifications": true,
|
||||
"FarmingOrder": 0,
|
||||
"FarmOffline": false,
|
||||
|
||||
@@ -53,36 +53,46 @@ namespace ConfigGenerator {
|
||||
NamesDescending
|
||||
}
|
||||
|
||||
[Category("\t\tCore")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
[Category("\tAdvanced")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool StartOnLaunch { get; set; } = true;
|
||||
|
||||
[Category("\t\tCore")]
|
||||
[JsonProperty]
|
||||
public string SteamLogin { get; set; } = null;
|
||||
|
||||
[Category("\t\tCore")]
|
||||
[JsonProperty]
|
||||
[PasswordPropertyText(true)]
|
||||
public string SteamPassword { get; set; } = null;
|
||||
|
||||
[Category("\tAccess")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ECryptoMethod PasswordFormat { get; set; } = ECryptoMethod.PlainText;
|
||||
|
||||
[Category("\tAccess")]
|
||||
[JsonProperty]
|
||||
public string SteamParentalPIN { get; set; } = "0";
|
||||
|
||||
[Category("\tAccess")]
|
||||
[JsonProperty]
|
||||
public string SteamApiKey { get; set; } = null;
|
||||
|
||||
[Category("\tAccess")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ulong SteamMasterID { get; set; } = 0;
|
||||
|
||||
[Category("\tAccess")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ulong SteamMasterClanID { get; set; } = 0;
|
||||
|
||||
[Category("\tPerformance")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool CardDropsRestricted { get; set; } = false;
|
||||
public bool CardDropsRestricted { get; set; } = true;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool DismissInventoryNotifications { get; set; } = true;
|
||||
@@ -93,15 +103,18 @@ namespace ConfigGenerator {
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool FarmOffline { get; set; } = false;
|
||||
|
||||
[Category("\tAdvanced")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool HandleOfflineMessages { get; set; } = false;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool AcceptGifts { get; set; } = false;
|
||||
|
||||
[Category("\tAdvanced")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool IsBotAccount { get; set; } = false;
|
||||
|
||||
[Category("\tAdvanced")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool SteamTradeMatcher { get; set; } = false;
|
||||
|
||||
@@ -117,12 +130,14 @@ namespace ConfigGenerator {
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool SendOnFarmingFinished { get; set; } = false;
|
||||
|
||||
[Category("\tAccess")]
|
||||
[JsonProperty]
|
||||
public string SteamTradeToken { get; set; } = null;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte SendTradePeriod { get; set; } = 0;
|
||||
|
||||
[Category("\tAdvanced")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte AcceptConfirmationsPeriod { get; set; } = 0;
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RunTime.cs" />
|
||||
<Compile Include="Tutorial.cs" />
|
||||
<EmbeddedResource Include="ConfigPage.resx">
|
||||
<DependentUpon>ConfigPage.cs</DependentUpon>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
@@ -50,57 +51,74 @@ namespace ConfigGenerator {
|
||||
// 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 };
|
||||
|
||||
[Category("\tDebugging")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool Debug { get; set; } = false;
|
||||
|
||||
[Category("\tAdvanced")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool Headless { get; set; } = false;
|
||||
|
||||
[Category("\tUpdates")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool AutoUpdates { get; set; } = true;
|
||||
|
||||
[Category("\tUpdates")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool AutoRestart { get; set; } = true;
|
||||
|
||||
[Category("\tUpdates")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public EUpdateChannel UpdateChannel { get; set; } = EUpdateChannel.Stable;
|
||||
|
||||
[Category("\tAdvanced")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ProtocolType SteamProtocol { get; set; } = DefaultSteamProtocol;
|
||||
|
||||
[Category("\tAccess")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ulong SteamOwnerID { get; set; } = 0;
|
||||
|
||||
[Category("\tPerformance")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte MaxFarmingTime { get; set; } = DefaultMaxFarmingTime;
|
||||
|
||||
[Category("\tPerformance")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte IdleFarmingPeriod { get; set; } = 3;
|
||||
|
||||
[Category("\tPerformance")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte FarmingDelay { get; set; } = DefaultFarmingDelay;
|
||||
|
||||
[Category("\tPerformance")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte LoginLimiterDelay { get; set; } = 10;
|
||||
|
||||
[Category("\tPerformance")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte InventoryLimiterDelay { get; set; } = 3;
|
||||
|
||||
[Category("\tPerformance")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte GiftsLimiterDelay { get; set; } = 1;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte MaxTradeHoldDuration { get; set; } = 15;
|
||||
|
||||
[Category("\tDebugging")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public bool ForceHttp { get; set; } = false;
|
||||
|
||||
[Category("\tDebugging")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public byte HttpTimeout { get; set; } = DefaultHttpTimeout;
|
||||
|
||||
[Category("\tAccess")]
|
||||
[JsonProperty]
|
||||
public string WCFHostname { get; set; } = "localhost";
|
||||
|
||||
[Category("\tAccess")]
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
public ushort WCFPort { get; set; } = DefaultWCFPort;
|
||||
|
||||
|
||||
33
ConfigGenerator/RunTime.cs
Normal file
33
ConfigGenerator/RunTime.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
_ _ _ ____ _ _____
|
||||
/ \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
/ _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
/ ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
/_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
|
||||
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;
|
||||
|
||||
namespace ConfigGenerator {
|
||||
internal static class Runtime {
|
||||
private static readonly Type MonoRuntime = Type.GetType("Mono.Runtime");
|
||||
|
||||
internal static bool IsRunningOnMono => MonoRuntime != null;
|
||||
}
|
||||
}
|
||||
@@ -57,8 +57,14 @@ namespace ConfigGenerator {
|
||||
Logging.LogGenericInfoWithoutStacktrace("You can now notice the main ASF Config Generator screen, it's really easy to use!");
|
||||
Logging.LogGenericInfoWithoutStacktrace("At the top of the window you can notice currently loaded configs, and 3 extra buttons for removing, renaming and adding new ones.");
|
||||
Logging.LogGenericInfoWithoutStacktrace("In the middle of the window you will be able to configure all config properties that are available for you.");
|
||||
Logging.LogGenericInfoWithoutStacktrace("In the top right corner you can find help button [?] which will redirect you to ASF wiki where you can find more information.");
|
||||
Logging.LogGenericInfoWithoutStacktrace("Please click the help button to continue.");
|
||||
if (!Runtime.IsRunningOnMono) {
|
||||
Logging.LogGenericInfoWithoutStacktrace("In the top right corner you can find help button [?] which will redirect you to ASF wiki where you can find more information.");
|
||||
Logging.LogGenericInfoWithoutStacktrace("Please click the help button to continue.");
|
||||
} else {
|
||||
Logging.LogGenericInfoWithoutStacktrace("Please visit ASF wiki if you're in doubt - you can find more information there.");
|
||||
Logging.LogGenericInfoWithoutStacktrace("Alright, let's start configuring our ASF. Click on the plus [+] button to add your first steam account to ASF!");
|
||||
NextPhase = EPhase.HelpFinished;
|
||||
}
|
||||
break;
|
||||
case EPhase.Help:
|
||||
Logging.LogGenericInfoWithoutStacktrace("Well done! On ASF wiki you can find detailed help about every config property you're going to configure in a moment.");
|
||||
|
||||
4
GUI/FodyWeavers.xml
Normal file
4
GUI/FodyWeavers.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Weavers>
|
||||
<Costura IncludeDebugSymbols='false' />
|
||||
</Weavers>
|
||||
@@ -12,6 +12,8 @@
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -199,9 +201,19 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="cirno.ico" />
|
||||
<None Include="FodyWeavers.xml" />
|
||||
<None Include="Resources\SteamUnknownAvatar.jpg" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Fody.1.30.0-beta01\build\dotnet\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.1.30.0-beta01\build\dotnet\Fody.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Costura.Fody.2.0.0-beta0018\build\Costura.Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.2.0.0-beta0018\build\Costura.Fody.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Fody.1.30.0-beta01\build\dotnet\Fody.targets" Condition="'$(OS)' != 'Unix' AND '$(ConfigurationName)' == 'Release' AND Exists('..\packages\Fody.1.30.0-beta01\build\dotnet\Fody.targets')" />
|
||||
<Import Project="..\packages\Costura.Fody.2.0.0-beta0018\build\Costura.Fody.targets" Condition="'$(OS)' != 'Unix' AND '$(ConfigurationName)' == 'Release' AND Exists('..\packages\Costura.Fody.2.0.0-beta0018\build\Costura.Fody.targets')" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Costura.Fody" version="2.0.0-beta0018" targetFramework="net461" developmentDependency="true" />
|
||||
<package id="Fody" version="1.30.0-beta01" targetFramework="net461" developmentDependency="true" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net461" />
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" />
|
||||
<package id="NLog" version="4.4.0-betaV15" targetFramework="net461" />
|
||||
|
||||
@@ -6,7 +6,7 @@ ArchiSteamFarm
|
||||
[](https://travis-ci.org/JustArchi/ArchiSteamFarm)
|
||||
[](./LICENSE-2.0.txt)
|
||||
[](https://github.com/JustArchi/ArchiSteamFarm/releases/latest)
|
||||
[](https://github.com/JustArchi/ArchiSteamFarm/releases)
|
||||
[](https://github.com/JustArchi/ArchiSteamFarm/releases/latest)
|
||||
|
||||
[](https://www.paypal.me/JustArchi/1usd)
|
||||
[](https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_)
|
||||
@@ -42,8 +42,10 @@ ASF officially supports Windows, Linux and OS X operating systems, including fol
|
||||
|
||||
- Windows 10 (Native)
|
||||
- Windows 8.1 (Native)
|
||||
- Windows 7 (Native)
|
||||
- Windows Vista (Native)
|
||||
- Windows 8 (Native)
|
||||
- Windows 7 SP1 (Native)
|
||||
- Windows Server 2012 R2 (Native)
|
||||
- Windows Server 2008 R2 SP1 (Native)
|
||||
- Debian 9 Stretch (Mono)
|
||||
- Debian 8 Jessie (Mono)
|
||||
- Ubuntu 16.04 (Mono)
|
||||
|
||||
Reference in New Issue
Block a user