mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-16 22:40:30 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ada8595bd | ||
|
|
bc64c43748 | ||
|
|
f4f7935d4c | ||
|
|
aacc0a1720 | ||
|
|
e5ee909b96 | ||
|
|
f3f444d0bd | ||
|
|
43d18b6d49 | ||
|
|
f24be67c8c | ||
|
|
6ce4f2941b | ||
|
|
ef5398fae8 | ||
|
|
ce600fdf42 | ||
|
|
7a6485775d | ||
|
|
d39e7a32d6 | ||
|
|
b4cbe85b36 | ||
|
|
4d83417c9d | ||
|
|
25bfbf4862 | ||
|
|
e539e1bdc7 | ||
|
|
b0f83fcd6d | ||
|
|
4880a4e60b |
@@ -50,11 +50,10 @@ matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
# We're building ASF with dotnet on latest versions of Linux and OS X
|
||||
# Ref: https://docs.travis-ci.com/user/ci-environment/#Virtualization-environments
|
||||
- os: linux
|
||||
# Ref: https://docs.travis-ci.com/user/trusty-ci-environment/
|
||||
# Ref: https://docs.travis-ci.com/user/reference/trusty/
|
||||
dist: trusty
|
||||
sudo: false
|
||||
- os: osx
|
||||
# Ref: https://docs.travis-ci.com/user/osx-ci-environment/
|
||||
# Ref: https://docs.travis-ci.com/user/reference/osx/
|
||||
osx_image: xcode9
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170628-02" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20170727-01" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="1.2.0-beta" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="1.2.0-beta" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<AssemblyVersion>3.0.0.6</AssemblyVersion>
|
||||
<FileVersion>3.0.0.6</FileVersion>
|
||||
<AssemblyVersion>3.0.0.9</AssemblyVersion>
|
||||
<FileVersion>3.0.0.9</FileVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ErrorReport>none</ErrorReport>
|
||||
<ApplicationIcon>ASF.ico</ApplicationIcon>
|
||||
|
||||
@@ -58,15 +58,15 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private const string SteamStoreURL = "http://" + SteamStoreHost;
|
||||
|
||||
private static readonly SemaphoreSlim InventorySemaphore = new SemaphoreSlim(1);
|
||||
private static readonly SemaphoreSlim InventorySemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
private static int Timeout = GlobalConfig.DefaultConnectionTimeout * 1000; // This must be int type
|
||||
|
||||
private readonly SemaphoreSlim ApiKeySemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim ApiKeySemaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly Bot Bot;
|
||||
private readonly SemaphoreSlim PublicInventorySemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim SessionSemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim TradeTokenSemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim PublicInventorySemaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim SessionSemaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim TradeTokenSemaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly WebBrowser WebBrowser;
|
||||
|
||||
private string CachedApiKey;
|
||||
@@ -74,6 +74,7 @@ namespace ArchiSteamFarm {
|
||||
private string CachedTradeToken;
|
||||
private DateTime LastSessionRefreshCheck = DateTime.MinValue;
|
||||
private ulong SteamID;
|
||||
private string VanityURL;
|
||||
|
||||
internal ArchiWebHandler(Bot bot) {
|
||||
Bot = bot ?? throw new ArgumentNullException(nameof(bot));
|
||||
@@ -867,12 +868,16 @@ namespace ArchiSteamFarm {
|
||||
|
||||
internal static void Init() => Timeout = Program.GlobalConfig.ConnectionTimeout * 1000;
|
||||
|
||||
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, string vanityURL = null) {
|
||||
if ((steamID == 0) || (universe == EUniverse.Invalid) || string.IsNullOrEmpty(webAPIUserNonce) || string.IsNullOrEmpty(parentalPin)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(universe) + " || " + nameof(webAPIUserNonce) + " || " + nameof(parentalPin));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(vanityURL)) {
|
||||
VanityURL = vanityURL;
|
||||
}
|
||||
|
||||
string sessionID = Convert.ToBase64String(Encoding.UTF8.GetBytes(steamID.ToString()));
|
||||
|
||||
// Generate an AES session key
|
||||
@@ -1104,7 +1109,7 @@ namespace ArchiSteamFarm {
|
||||
return false;
|
||||
}
|
||||
|
||||
string request = SteamCommunityURL + "/profiles/" + SteamID + "/ajaxunpackbooster";
|
||||
string request = GetAbsoluteProfileURL() + "/ajaxunpackbooster";
|
||||
Dictionary<string, string> data = new Dictionary<string, string>(3) {
|
||||
{ "sessionid", sessionID },
|
||||
{ "appid", appID.ToString() },
|
||||
@@ -1115,6 +1120,14 @@ namespace ArchiSteamFarm {
|
||||
return response?.Result == EResult.OK;
|
||||
}
|
||||
|
||||
private string GetAbsoluteProfileURL() {
|
||||
if (!string.IsNullOrEmpty(VanityURL)) {
|
||||
return SteamCommunityURL + "/id/" + VanityURL;
|
||||
}
|
||||
|
||||
return SteamCommunityURL + "/profiles/" + SteamID;
|
||||
}
|
||||
|
||||
private async Task<string> GetApiKey() {
|
||||
if (CachedApiKey != null) {
|
||||
// We fetched API key already, and either got valid one, or permanent AccessDenied
|
||||
|
||||
@@ -53,8 +53,8 @@ namespace ArchiSteamFarm {
|
||||
|
||||
internal static readonly ConcurrentDictionary<string, Bot> Bots = new ConcurrentDictionary<string, Bot>();
|
||||
|
||||
private static readonly SemaphoreSlim GiftsSemaphore = new SemaphoreSlim(1);
|
||||
private static readonly SemaphoreSlim LoginSemaphore = new SemaphoreSlim(1);
|
||||
private static readonly SemaphoreSlim GiftsSemaphore = new SemaphoreSlim(1, 1);
|
||||
private static readonly SemaphoreSlim LoginSemaphore = new SemaphoreSlim(1, 1);
|
||||
private static readonly SteamConfiguration SteamConfiguration = new SteamConfiguration();
|
||||
|
||||
internal readonly ArchiLogger ArchiLogger;
|
||||
@@ -73,15 +73,16 @@ namespace ArchiSteamFarm {
|
||||
private readonly BotDatabase BotDatabase;
|
||||
private readonly string BotName;
|
||||
private readonly CallbackManager CallbackManager;
|
||||
private readonly SemaphoreSlim CallbackSemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim CallbackSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
[JsonProperty]
|
||||
private readonly CardsFarmer CardsFarmer;
|
||||
|
||||
private readonly ConcurrentHashSet<ulong> HandledGifts = new ConcurrentHashSet<ulong>();
|
||||
private readonly Timer HeartBeatTimer;
|
||||
private readonly SemaphoreSlim InitializationSemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim LootingSemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim InitializationSemaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim LootingSemaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim PICSSemaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly Statistics Statistics;
|
||||
private readonly SteamApps SteamApps;
|
||||
private readonly SteamClient SteamClient;
|
||||
@@ -235,6 +236,8 @@ namespace ArchiSteamFarm {
|
||||
CardsFarmer.Dispose();
|
||||
HeartBeatTimer.Dispose();
|
||||
InitializationSemaphore.Dispose();
|
||||
LootingSemaphore.Dispose();
|
||||
PICSSemaphore.Dispose();
|
||||
Trading.Dispose();
|
||||
|
||||
// Those are objects that might be null and the check should be in-place
|
||||
@@ -349,11 +352,15 @@ namespace ArchiSteamFarm {
|
||||
|
||||
AsyncJobMultiple<SteamApps.PICSProductInfoCallback>.ResultSet productInfoResultSet;
|
||||
|
||||
await PICSSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
productInfoResultSet = await SteamApps.PICSGetProductInfo(appID, null, false);
|
||||
} catch (Exception e) {
|
||||
ArchiLogger.LogGenericException(e);
|
||||
return (0, DateTime.MinValue);
|
||||
} finally {
|
||||
PICSSemaphore.Release();
|
||||
}
|
||||
|
||||
// ReSharper disable once LoopCanBePartlyConvertedToQuery - C# 7.0 out can't be used within LINQ query yet | https://github.com/dotnet/roslyn/issues/15619
|
||||
@@ -452,11 +459,15 @@ namespace ArchiSteamFarm {
|
||||
internal async Task<Dictionary<uint, HashSet<uint>>> GetAppIDsToPackageIDs(IEnumerable<uint> packageIDs) {
|
||||
AsyncJobMultiple<SteamApps.PICSProductInfoCallback>.ResultSet productInfoResultSet;
|
||||
|
||||
await PICSSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
productInfoResultSet = await SteamApps.PICSGetProductInfo(Enumerable.Empty<uint>(), packageIDs);
|
||||
} catch (Exception e) {
|
||||
ArchiLogger.LogGenericException(e);
|
||||
return null;
|
||||
} finally {
|
||||
PICSSemaphore.Release();
|
||||
}
|
||||
|
||||
Dictionary<uint, HashSet<uint>> result = new Dictionary<uint, HashSet<uint>>();
|
||||
@@ -510,6 +521,17 @@ namespace ArchiSteamFarm {
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void IdleGame(uint gameID) => IdleGames(gameID.ToEnumerable());
|
||||
|
||||
internal void IdleGames(IEnumerable<uint> gameIDs) {
|
||||
if (gameIDs == null) {
|
||||
ArchiLogger.LogNullError(nameof(gameIDs));
|
||||
return;
|
||||
}
|
||||
|
||||
ArchiHandler.PlayGames(gameIDs, BotConfig.CustomGamePlayedWhileFarming);
|
||||
}
|
||||
|
||||
internal static async Task InitializeSteamConfiguration(ProtocolTypes protocolTypes, uint cellID, InMemoryServerListProvider serverListProvider) {
|
||||
if (serverListProvider == null) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(serverListProvider));
|
||||
@@ -635,17 +657,6 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
internal void PlayGame(uint gameID, string gameName = null) => PlayGames(gameID.ToEnumerable(), gameName);
|
||||
|
||||
internal void PlayGames(IEnumerable<uint> gameIDs, string gameName = null) {
|
||||
if (gameIDs == null) {
|
||||
ArchiLogger.LogNullError(nameof(gameIDs));
|
||||
return;
|
||||
}
|
||||
|
||||
ArchiHandler.PlayGames(gameIDs, gameName);
|
||||
}
|
||||
|
||||
internal async Task<bool> RefreshSession() {
|
||||
if (!IsConnectedAndLoggedOn) {
|
||||
return false;
|
||||
@@ -1123,7 +1134,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
try {
|
||||
if (DateTime.UtcNow.Subtract(ArchiHandler.LastPacketReceived).TotalSeconds > MinHeartBeatTTL) {
|
||||
await SteamApps.PICSGetProductInfo(0, null);
|
||||
await SteamFriends.RequestProfileInfo(SteamClient.SteamID);
|
||||
}
|
||||
|
||||
HeartBeatFailures = 0;
|
||||
@@ -1810,7 +1821,7 @@ namespace ArchiSteamFarm {
|
||||
ArchiLogger.LogGenericWarning(Strings.BotAccountLocked);
|
||||
}
|
||||
|
||||
if ((callback.CellID != 0) && (Program.GlobalDatabase.CellID != callback.CellID)) {
|
||||
if (callback.CellID != 0) {
|
||||
Program.GlobalDatabase.CellID = callback.CellID;
|
||||
}
|
||||
|
||||
@@ -1832,7 +1843,7 @@ namespace ArchiSteamFarm {
|
||||
SetUserInput(ASF.EUserInputType.SteamParentalPIN, steamParentalPIN);
|
||||
}
|
||||
|
||||
if (!await ArchiWebHandler.Init(callback.ClientSteamID, SteamClient.Universe, callback.WebAPIUserNonce, BotConfig.SteamParentalPIN).ConfigureAwait(false)) {
|
||||
if (!await ArchiWebHandler.Init(callback.ClientSteamID, SteamClient.Universe, callback.WebAPIUserNonce, BotConfig.SteamParentalPIN, callback.VanityURL).ConfigureAwait(false)) {
|
||||
if (!await RefreshSession().ConfigureAwait(false)) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -58,9 +58,9 @@ namespace ArchiSteamFarm {
|
||||
);
|
||||
|
||||
private readonly Bot Bot;
|
||||
private readonly SemaphoreSlim EventSemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim FarmingSemaphore = new SemaphoreSlim(1);
|
||||
private readonly ManualResetEventSlim FarmResetEvent = new ManualResetEventSlim(false);
|
||||
private readonly SemaphoreSlim EventSemaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim FarmingInitializationSemaphore = new SemaphoreSlim(1, 1);
|
||||
private readonly SemaphoreSlim FarmingResetSemaphore = new SemaphoreSlim(0, 1);
|
||||
private readonly Timer IdleFarmingTimer;
|
||||
|
||||
[JsonProperty]
|
||||
@@ -87,8 +87,8 @@ namespace ArchiSteamFarm {
|
||||
public void Dispose() {
|
||||
// Those are objects that are always being created if constructor doesn't throw exception
|
||||
EventSemaphore.Dispose();
|
||||
FarmingSemaphore.Dispose();
|
||||
FarmResetEvent.Dispose();
|
||||
FarmingInitializationSemaphore.Dispose();
|
||||
FarmingResetSemaphore.Dispose();
|
||||
|
||||
// Those are objects that might be null and the check should be in-place
|
||||
IdleFarmingTimer?.Dispose();
|
||||
@@ -140,7 +140,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
internal async Task OnNewItemsNotification() {
|
||||
if (NowFarming) {
|
||||
FarmResetEvent.Set();
|
||||
FarmingResetSemaphore.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
await FarmingSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
await FarmingInitializationSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
if (NowFarming || Paused || !Bot.IsPlayingPossible) {
|
||||
@@ -231,7 +231,7 @@ namespace ArchiSteamFarm {
|
||||
KeepFarming = NowFarming = true;
|
||||
Utilities.StartBackgroundFunction(Farm);
|
||||
} finally {
|
||||
FarmingSemaphore.Release();
|
||||
FarmingInitializationSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
await FarmingSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
await FarmingInitializationSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
if (!NowFarming) {
|
||||
@@ -248,7 +248,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
KeepFarming = false;
|
||||
FarmResetEvent.Set();
|
||||
FarmingResetSemaphore.Release();
|
||||
|
||||
for (byte i = 0; (i < 5) && NowFarming; i++) {
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
@@ -261,7 +261,7 @@ namespace ArchiSteamFarm {
|
||||
Bot.ArchiLogger.LogGenericInfo(Strings.IdlingStopped);
|
||||
Bot.OnFarmingStopped();
|
||||
} finally {
|
||||
FarmingSemaphore.Release();
|
||||
FarmingInitializationSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,65 +556,68 @@ namespace ArchiSteamFarm {
|
||||
// If we have restricted card drops, we use complex algorithm
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Complex"));
|
||||
while (GamesToFarm.Count > 0) {
|
||||
HashSet<Game> playableGamesToFarmSolo = new HashSet<Game>();
|
||||
foreach (Game game in GamesToFarm.Where(game => game.HoursPlayed >= HoursToBump)) {
|
||||
if (await IsPlayableGame(game).ConfigureAwait(false)) {
|
||||
playableGamesToFarmSolo.Add(game);
|
||||
HashSet<Game> gamesToCheck = new HashSet<Game>(GamesToFarm.Where(game => game.HoursPlayed >= HoursToBump));
|
||||
|
||||
foreach (Game game in gamesToCheck) {
|
||||
if (!await IsPlayableGame(game).ConfigureAwait(false)) {
|
||||
GamesToFarm.Remove(game);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (await FarmSolo(game).ConfigureAwait(false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
|
||||
gamesToCheck = new HashSet<Game>(GamesToFarm.OrderByDescending(game => game.HoursPlayed));
|
||||
HashSet<Game> playableGamesToFarmMultiple = new HashSet<Game>();
|
||||
|
||||
foreach (Game game in gamesToCheck) {
|
||||
if (!await IsPlayableGame(game).ConfigureAwait(false)) {
|
||||
GamesToFarm.Remove(game);
|
||||
continue;
|
||||
}
|
||||
|
||||
playableGamesToFarmMultiple.Add(game);
|
||||
if (playableGamesToFarmMultiple.Count >= ArchiHandler.MaxGamesPlayedConcurrently) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (playableGamesToFarmSolo.Count > 0) {
|
||||
while (playableGamesToFarmSolo.Count > 0) {
|
||||
Game playableGame = playableGamesToFarmSolo.First();
|
||||
if (await FarmSolo(playableGame).ConfigureAwait(false)) {
|
||||
playableGamesToFarmSolo.Remove(playableGame);
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (playableGamesToFarmMultiple.Count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (await FarmMultiple(playableGamesToFarmMultiple).ConfigureAwait(false)) {
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingFinishedForGames, string.Join(", ", playableGamesToFarmMultiple.Select(game => game.AppID))));
|
||||
} else {
|
||||
HashSet<Game> playableGamesToFarmMultiple = new HashSet<Game>();
|
||||
foreach (Game game in GamesToFarm.Where(game => game.HoursPlayed < HoursToBump).OrderByDescending(game => game.HoursPlayed)) {
|
||||
if (await IsPlayableGame(game).ConfigureAwait(false)) {
|
||||
playableGamesToFarmMultiple.Add(game);
|
||||
}
|
||||
|
||||
if (playableGamesToFarmMultiple.Count >= ArchiHandler.MaxGamesPlayedConcurrently) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (FarmMultiple(playableGamesToFarmMultiple)) {
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.IdlingFinishedForGames, string.Join(", ", playableGamesToFarmMultiple.Select(game => game.AppID))));
|
||||
} else {
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If we have unrestricted card drops, we use simple algorithm
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ChosenFarmingAlgorithm, "Simple"));
|
||||
|
||||
while (GamesToFarm.Count > 0) {
|
||||
Game playableGame = null;
|
||||
foreach (Game game in GamesToFarm) {
|
||||
HashSet<Game> gamesToCheck = new HashSet<Game>(GamesToFarm);
|
||||
|
||||
foreach (Game game in gamesToCheck) {
|
||||
if (!await IsPlayableGame(game).ConfigureAwait(false)) {
|
||||
GamesToFarm.Remove(game);
|
||||
continue;
|
||||
}
|
||||
|
||||
playableGame = game;
|
||||
break;
|
||||
}
|
||||
|
||||
if (playableGame != null) {
|
||||
if (await FarmSolo(playableGame).ConfigureAwait(false)) {
|
||||
if (await FarmSolo(game).ConfigureAwait(false)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
NowFarming = false;
|
||||
return;
|
||||
NowFarming = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ((await IsAnythingToFarm().ConfigureAwait(false)).GetValueOrDefault());
|
||||
@@ -638,7 +641,7 @@ namespace ArchiSteamFarm {
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningIdlingGameMismatch, game.AppID, game.GameName, game.PlayableAppID));
|
||||
}
|
||||
|
||||
Bot.PlayGame(game.PlayableAppID, Bot.BotConfig.CustomGamePlayedWhileFarming);
|
||||
Bot.IdleGame(game.PlayableAppID);
|
||||
DateTime endFarmingDate = DateTime.UtcNow.AddHours(Program.GlobalConfig.MaxFarmingTime);
|
||||
|
||||
bool? keepFarming = await ShouldFarm(game).ConfigureAwait(false);
|
||||
@@ -646,8 +649,7 @@ namespace ArchiSteamFarm {
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdling, game.AppID, game.GameName));
|
||||
|
||||
DateTime startFarmingPeriod = DateTime.UtcNow;
|
||||
if (FarmResetEvent.Wait(60 * 1000 * Program.GlobalConfig.FarmingDelay)) {
|
||||
FarmResetEvent.Reset();
|
||||
if (await FarmingResetSemaphore.WaitAsync(60 * 1000 * Program.GlobalConfig.FarmingDelay).ConfigureAwait(false)) {
|
||||
success = KeepFarming;
|
||||
}
|
||||
|
||||
@@ -665,7 +667,7 @@ namespace ArchiSteamFarm {
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool FarmHours(ConcurrentHashSet<Game> games) {
|
||||
private async Task<bool> FarmHours(ConcurrentHashSet<Game> games) {
|
||||
if ((games == null) || (games.Count == 0)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(games));
|
||||
return false;
|
||||
@@ -682,15 +684,14 @@ namespace ArchiSteamFarm {
|
||||
return true;
|
||||
}
|
||||
|
||||
Bot.PlayGames(games.Select(game => game.AppID), Bot.BotConfig.CustomGamePlayedWhileFarming);
|
||||
Bot.IdleGames(games.Select(game => game.PlayableAppID));
|
||||
|
||||
bool success = true;
|
||||
while (maxHour < 2) {
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.StillIdlingList, string.Join(", ", games.Select(game => game.AppID))));
|
||||
|
||||
DateTime startFarmingPeriod = DateTime.UtcNow;
|
||||
if (FarmResetEvent.Wait(60 * 1000 * Program.GlobalConfig.FarmingDelay)) {
|
||||
FarmResetEvent.Reset();
|
||||
if (await FarmingResetSemaphore.WaitAsync(60 * 1000 * Program.GlobalConfig.FarmingDelay).ConfigureAwait(false)) {
|
||||
success = KeepFarming;
|
||||
}
|
||||
|
||||
@@ -711,7 +712,7 @@ namespace ArchiSteamFarm {
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool FarmMultiple(IEnumerable<Game> games) {
|
||||
private async Task<bool> FarmMultiple(IEnumerable<Game> games) {
|
||||
if (games == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(games));
|
||||
return false;
|
||||
@@ -721,7 +722,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.NowIdlingList, string.Join(", ", CurrentGamesFarming.Select(game => game.AppID))));
|
||||
|
||||
bool result = FarmHours(CurrentGamesFarming);
|
||||
bool result = await FarmHours(CurrentGamesFarming).ConfigureAwait(false);
|
||||
CurrentGamesFarming.Clear();
|
||||
return result;
|
||||
}
|
||||
@@ -926,7 +927,7 @@ namespace ArchiSteamFarm {
|
||||
case BotConfig.EFarmingOrder.RedeemDateTimesDescending:
|
||||
Dictionary<uint, DateTime> redeemDates = new Dictionary<uint, DateTime>(GamesToFarm.Count);
|
||||
|
||||
foreach (Game game in gamesToFarm) {
|
||||
foreach (Game game in GamesToFarm) {
|
||||
DateTime redeemDate = DateTime.MinValue;
|
||||
if (Program.GlobalDatabase.AppIDsToPackageIDs.TryGetValue(game.AppID, out ConcurrentHashSet<uint> packageIDs)) {
|
||||
// ReSharper disable once LoopCanBePartlyConvertedToQuery - C# 7.0 out can't be used within LINQ query yet | https://github.com/dotnet/roslyn/issues/15619
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace ArchiSteamFarm {
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
private readonly HashSet<T> BackingCollection = new HashSet<T>();
|
||||
private readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim SemaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
|
||||
public bool Add(T item) {
|
||||
SemaphoreSlim.Wait();
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace ArchiSteamFarm {
|
||||
internal readonly bool Statistics = true;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
internal readonly ProtocolTypes SteamProtocols = ProtocolTypes.All;
|
||||
internal readonly ProtocolTypes SteamProtocols = ProtocolTypes.Tcp;
|
||||
|
||||
[JsonProperty(Required = Required.DisallowNull)]
|
||||
internal readonly EUpdateChannel UpdateChannel = EUpdateChannel.Stable;
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private readonly object FileLock = new object();
|
||||
|
||||
private readonly SemaphoreSlim PackagesRefreshSemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim PackagesRefreshSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
internal uint CellID {
|
||||
get => _CellID;
|
||||
|
||||
@@ -673,5 +673,8 @@ StackTrace:
|
||||
<value>Procházení fronty doporučení #{0} dokončeno.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>{0}/{1} botů již vlastní všechny uvedené hry.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -673,5 +673,8 @@ StackTrace:
|
||||
<value>Fertig mit Löschung der Steam Entdeckungsliste #{0}.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>Es gibt {0}/{1}-Bots, die bereits alle geprüften Spiele besitzen.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -673,5 +673,8 @@ StackTrace:
|
||||
<value>Ολοκληρώθηκε η εκκαθάριση σειράς ανακαλύψεων Steam #{0}.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>Υπάρχουν {0}/{1} bot που κατέχουν ήδη όλα τα παιχνίδια για τα οποία γίνεται έλεγχος.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -289,7 +289,9 @@
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
<data name="IPCReady" xml:space="preserve">
|
||||
<value>Server IPC siap!</value>
|
||||
</data>
|
||||
|
||||
<data name="BotAlreadyStopped" xml:space="preserve">
|
||||
<value>Bot ini sudah berhenti!</value>
|
||||
|
||||
@@ -184,14 +184,19 @@ StackTrace:
|
||||
<data name="ErrorUpdateCheckFailed" xml:space="preserve">
|
||||
<value>최신 버전을 확인할 수 없습니다!</value>
|
||||
</data>
|
||||
|
||||
<data name="ErrorUpdateNoAssetForThisVersion" xml:space="preserve">
|
||||
<value>현재 실행 중인 버전과 관련된 자산이 없으므로 업데이트를 진행할 수 없습니다! 해당 버전으로 자동 업데이트가 불가능합니다.</value>
|
||||
</data>
|
||||
<data name="ErrorUpdateNoAssets" xml:space="preserve">
|
||||
<value>해당 버전이 아무 내용도 포함되어 있지 않아 업데이트를 진행할 수 없습니다!</value>
|
||||
</data>
|
||||
<data name="ErrorUserInputRunningInHeadlessMode" xml:space="preserve">
|
||||
<value>사용자 입력 요청을 받았지만, 프로세스는 Headless 모드로 실행 중입니다.</value>
|
||||
</data>
|
||||
|
||||
<data name="ErrorIPCAccessDenied" xml:space="preserve">
|
||||
<value>SteamOwnerID가 설정되지 않았기 때문에 요청을 거절합니다!</value>
|
||||
<comment>SteamOwnerID is name of bot config property, it should not be translated</comment>
|
||||
</data>
|
||||
<data name="Exiting" xml:space="preserve">
|
||||
<value>종료 중...</value>
|
||||
</data>
|
||||
@@ -241,7 +246,10 @@ StackTrace:
|
||||
<data name="UpdateCheckingNewVersion" xml:space="preserve">
|
||||
<value>새로운 버전 확인 중...</value>
|
||||
</data>
|
||||
|
||||
<data name="UpdateDownloadingNewVersion" xml:space="preserve">
|
||||
<value>새로운 버전을 내려받는 중: {0} ({1} MB).... 기다리는 동안, 이 프로그램이 고맙다면, 기부하는 것을 고려해보세요! :)</value>
|
||||
<comment>{0} will be replaced by version string, {1} will be replaced by update size (in megabytes)</comment>
|
||||
</data>
|
||||
<data name="UpdateFinished" xml:space="preserve">
|
||||
<value>업데이트 작업 완료!</value>
|
||||
</data>
|
||||
@@ -280,7 +288,10 @@ StackTrace:
|
||||
<value>등록되지 않은 {0}의 값을 입력하세요: </value>
|
||||
<comment>{0} will be replaced by property name. Please note that this translation should end with space</comment>
|
||||
</data>
|
||||
|
||||
<data name="UserInputIPCHost" xml:space="preserve">
|
||||
<value>IPC 호스트를 입력하세요: </value>
|
||||
<comment>Please note that this translation should end with space</comment>
|
||||
</data>
|
||||
<data name="WarningUnknownValuePleaseReport" xml:space="preserve">
|
||||
<value>{0}의 알 수 없는 값을 받았습니다. 이것을 보고 바랍니다: {1}</value>
|
||||
<comment>{0} will be replaced by object's name, {1} will be replaced by value for that object</comment>
|
||||
@@ -289,10 +300,20 @@ StackTrace:
|
||||
<value>동시에 {0}개 이상의 게임들을 플레이하는 것은 불가능합니다. {1}에 의해 단지 {0}개의 항목만 사용될 것입니다!</value>
|
||||
<comment>{0} will be replaced by max number of games, {1} will be replaced by name of the configuration property</comment>
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="ErrorIPCAddressAccessDeniedException" xml:space="preserve">
|
||||
<value>AddressAccessDeniedException로 인해 IPC 서비스가 시작될 수 없습니다! ASF에서 제공하는 IPC 서비스를 사용하고 싶다면, ASF를 관리자 모드로 실행하거나 적절한 권한을 줘야 합니다!</value>
|
||||
</data>
|
||||
<data name="IPCAnswered" xml:space="preserve">
|
||||
<value>{0} IPC 명령에 대한 응답: {1}</value>
|
||||
<comment>{0} will be replaced by IPC command, {1} will be replaced by IPC answer</comment>
|
||||
</data>
|
||||
<data name="IPCReady" xml:space="preserve">
|
||||
<value>IPC 서버 준비 완료!</value>
|
||||
</data>
|
||||
<data name="IPCStarting" xml:space="preserve">
|
||||
<value>{0} 에서 IPC 서버 시작...</value>
|
||||
<comment>{0} will be replaced by IPC hostname</comment>
|
||||
</data>
|
||||
<data name="BotAlreadyStopped" xml:space="preserve">
|
||||
<value>이 봇은 이미 중지되어 있습니다!</value>
|
||||
</data>
|
||||
@@ -652,5 +673,8 @@ StackTrace:
|
||||
<value>스팀 맞춤 대기열 #{0}을 지웠습니다.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>게임을 확인 중인 {0}/{1} 개의 봇이 있습니다.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -670,5 +670,8 @@
|
||||
<value>Baigta peržiūrėti Steam atradimo eilė #{0}.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>Šiuo metu {0}/{1} botai turi visus tikrinamus žaidimus.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -673,5 +673,8 @@ StackTrace:
|
||||
<value>Steam-ontdekkingswachtrij voltooid #{0}.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>Er zijn {0}/{1} bots die de gecontroleerde spellen al in bezit hebben.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -673,5 +673,8 @@ StackTrace:
|
||||
<value>Steam-ontdekkingswachtrij voltooid #{0}.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>Er zijn {0}/{1} bots die de gecontroleerde spellen al in bezit hebben.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -673,5 +673,8 @@ StackTrace:
|
||||
<value>Limpeza da lista de descoberta da Steam #{0} concluída.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>Os bots {0}/{1} já possuem todos os jogos que estão sendo verificados.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -674,5 +674,8 @@ inválidas, abortando!</value>
|
||||
<value>Fila de exploração da Steam feita #{0}.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>Os bots {0}/{1} já possuem todos os jogos que está sendo verificados.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -673,5 +673,8 @@ StackTrace:
|
||||
<value>S-a terminat ștergerea cozii pentru lista de descoperiri Steam #{0}.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>Există {0}/{1} boți care dețin deja toate jocurile verificate.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -673,5 +673,8 @@ Yığın izleme:
|
||||
<value>Steam keşif kuyruğu temizlenmesi bitti #{0}.</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>{0}/{1} bot zaten sahip olunan tüm oyunları denetliyor.</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -181,14 +181,19 @@
|
||||
<data name="ErrorUpdateCheckFailed" xml:space="preserve">
|
||||
<value>无法检查最新版本 !</value>
|
||||
</data>
|
||||
|
||||
<data name="ErrorUpdateNoAssetForThisVersion" xml:space="preserve">
|
||||
<value>无法继续更新,因为没有与当前正在运行的版本相关的版本! 无法自动更新到该版本。</value>
|
||||
</data>
|
||||
<data name="ErrorUpdateNoAssets" xml:space="preserve">
|
||||
<value>不能进行更新,因为此版本没有任何资源!</value>
|
||||
</data>
|
||||
<data name="ErrorUserInputRunningInHeadlessMode" xml:space="preserve">
|
||||
<value>收到一个用户输入请求,但进程目前正在以无显示模式运行 !</value>
|
||||
</data>
|
||||
|
||||
<data name="ErrorIPCAccessDenied" xml:space="preserve">
|
||||
<value>拒绝处理该请求,因为未设置 SteamOwnerID !</value>
|
||||
<comment>SteamOwnerID is name of bot config property, it should not be translated</comment>
|
||||
</data>
|
||||
<data name="Exiting" xml:space="preserve">
|
||||
<value>正在退出...</value>
|
||||
</data>
|
||||
@@ -238,7 +243,10 @@
|
||||
<data name="UpdateCheckingNewVersion" xml:space="preserve">
|
||||
<value>正在检查新版本...</value>
|
||||
</data>
|
||||
|
||||
<data name="UpdateDownloadingNewVersion" xml:space="preserve">
|
||||
<value>更新中: {0} ({1} MB)...... 在你等待的时候,可以考虑趁现在进行捐赠!:)</value>
|
||||
<comment>{0} will be replaced by version string, {1} will be replaced by update size (in megabytes)</comment>
|
||||
</data>
|
||||
<data name="UpdateFinished" xml:space="preserve">
|
||||
<value>更新完毕</value>
|
||||
</data>
|
||||
@@ -277,7 +285,10 @@
|
||||
<value>请输入非正式的值 {0}: </value>
|
||||
<comment>{0} will be replaced by property name. Please note that this translation should end with space</comment>
|
||||
</data>
|
||||
|
||||
<data name="UserInputIPCHost" xml:space="preserve">
|
||||
<value>请输入你的IPC主机: </value>
|
||||
<comment>Please note that this translation should end with space</comment>
|
||||
</data>
|
||||
<data name="WarningUnknownValuePleaseReport" xml:space="preserve">
|
||||
<value>收到的{0} 为未知值,请报告此值:{1}</value>
|
||||
<comment>{0} will be replaced by object's name, {1} will be replaced by value for that object</comment>
|
||||
@@ -286,10 +297,20 @@
|
||||
<value>目前无法同时挂 {0} 个以上的游戏,只有 {1} 里面的前 {0} 个游戏可用!</value>
|
||||
<comment>{0} will be replaced by max number of games, {1} will be replaced by name of the configuration property</comment>
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
|
||||
<data name="ErrorIPCAddressAccessDeniedException" xml:space="preserve">
|
||||
<value>由于目标地址访问受拒绝,无法启动 IPC 服务 !如果你想要使用ASF提供的 IPC 服务,请用管理员身份运行,或者给予更高的权限。</value>
|
||||
</data>
|
||||
<data name="IPCAnswered" xml:space="preserve">
|
||||
<value>IPC 命令响应︰ {0} 及 {1}</value>
|
||||
<comment>{0} will be replaced by IPC command, {1} will be replaced by IPC answer</comment>
|
||||
</data>
|
||||
<data name="IPCReady" xml:space="preserve">
|
||||
<value>IPC 服务已就绪 !</value>
|
||||
</data>
|
||||
<data name="IPCStarting" xml:space="preserve">
|
||||
<value>在 {0} 上的启动 IPC 服务...</value>
|
||||
<comment>{0} will be replaced by IPC hostname</comment>
|
||||
</data>
|
||||
<data name="BotAlreadyStopped" xml:space="preserve">
|
||||
<value>这个帐号已停止运行!</value>
|
||||
</data>
|
||||
@@ -649,5 +670,8 @@
|
||||
<value>已完成Steam探索队列 #{0}。</value>
|
||||
<comment>{0} will be replaced by queue number</comment>
|
||||
</data>
|
||||
|
||||
<data name="BotOwnsOverview" xml:space="preserve">
|
||||
<value>{0}/{1} 个BOT已经拥有所有正在被检查的游戏。</value>
|
||||
<comment>{0} will be replaced by number of bots that already own games being checked, {1} will be replaced by total number of bots that were checked during the process</comment>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -42,14 +42,14 @@ namespace ArchiSteamFarm {
|
||||
private const byte CodeInterval = 30;
|
||||
|
||||
private static readonly char[] CodeCharacters = { '2', '3', '4', '5', '6', '7', '8', '9', 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'T', 'V', 'W', 'X', 'Y' };
|
||||
private static readonly SemaphoreSlim TimeSemaphore = new SemaphoreSlim(1);
|
||||
private static readonly SemaphoreSlim TimeSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
private static int? SteamTimeDifference;
|
||||
|
||||
// "ERROR" is being used by SteamDesktopAuthenticator
|
||||
internal bool HasCorrectDeviceID => !string.IsNullOrEmpty(DeviceID) && !DeviceID.Equals("ERROR");
|
||||
|
||||
private readonly SemaphoreSlim ConfirmationsSemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim ConfirmationsSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
#pragma warning disable 649
|
||||
[JsonProperty(PropertyName = "identity_secret", Required = Required.Always)]
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace ArchiSteamFarm {
|
||||
private const string URL = "https://" + SharedInfo.StatisticsServer;
|
||||
|
||||
private readonly Bot Bot;
|
||||
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
private DateTime LastAnnouncementCheck = DateTime.MinValue;
|
||||
private DateTime LastHeartBeat = DateTime.MinValue;
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private readonly Bot Bot;
|
||||
private readonly ConcurrentHashSet<ulong> IgnoredTrades = new ConcurrentHashSet<ulong>();
|
||||
private readonly SemaphoreSlim TradesSemaphore = new SemaphoreSlim(1);
|
||||
private readonly SemaphoreSlim TradesSemaphore = new SemaphoreSlim(1, 1);
|
||||
|
||||
private bool ParsingScheduled;
|
||||
|
||||
|
||||
@@ -535,7 +535,17 @@ namespace ArchiSteamFarm {
|
||||
ushort status = (ushort) responseMessage.StatusCode;
|
||||
if ((status >= 300) && (status <= 399) && (maxRedirections > 0)) {
|
||||
redirectUri = responseMessage.Headers.Location;
|
||||
if (!redirectUri.IsAbsoluteUri) {
|
||||
|
||||
if (redirectUri.IsAbsoluteUri) {
|
||||
switch (redirectUri.Scheme) {
|
||||
case "http":
|
||||
case "https":
|
||||
break;
|
||||
default:
|
||||
// Invalid ones such as "steammobile"
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
redirectUri = new Uri(requestUri.GetLeftPart(UriPartial.Authority) + redirectUri);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
"OptimizationMode": 0,
|
||||
"Statistics": true,
|
||||
"SteamOwnerID": 0,
|
||||
"SteamProtocols": 7,
|
||||
"SteamProtocols": 1,
|
||||
"UpdateChannel": 1
|
||||
}
|
||||
@@ -42,7 +42,7 @@ deploy:
|
||||
- provider: GitHub
|
||||
tag: $(appveyor_repo_tag_name)
|
||||
release: ArchiSteamFarm V$(appveyor_repo_tag_name)
|
||||
description: '**NOTICE:** Pre-releases are experimental versions that often contain unpatched bugs, work-in-progress features or rewritten implementations. If you don''t consider yourself advanced user, please download **[latest stable release](https://github.com/JustArchi/ArchiSteamFarm/releases/latest)** instead. Pre-release versions are dedicated to users who know how to report bugs, deal with issues and give feedback - no technical support will be given. Check out ASF **[release cycle](https://github.com/JustArchi/ArchiSteamFarm/wiki/Release-cycle)** if you''d like to learn more.\n\n---\n\nThis is automated AppVeyor GitHub deployment, human-readable changelog should be available soon. In the meantime please refer to **[GitHub commits](https://github.com/JustArchi/ArchiSteamFarm/commits/$(appveyor_repo_tag_name))**.\n\n---\n\nASF is available for free. If you''re grateful for what we''re doing, please consider donating. Developing ASF requires massive amount of time and knowledge, especially when it comes to Steam (and its problems). Even 1$ is highly appreciated and shows that you care!\n\n [](https://www.patreon.com/JustArchi) [](https://www.paypal.me/JustArchi/1usd) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4) [](https://blockchain.info/payment_request?address=1Archi6M1r5b41Rvn1SY2FfJAzsrEUT7aT) [](https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_)'
|
||||
description: '### **NOTICE:** Pre-releases are experimental versions that often contain unpatched bugs, work-in-progress features or rewritten implementations. If you don''t consider yourself advanced user, please download **[latest stable release](https://github.com/JustArchi/ArchiSteamFarm/releases/latest)** instead. Pre-release versions are dedicated to users who know how to report bugs, deal with issues and give feedback - no technical support will be given. Check out ASF **[release cycle](https://github.com/JustArchi/ArchiSteamFarm/wiki/Release-cycle)** if you''d like to learn more.\n\n---\n\nThis is automated AppVeyor GitHub deployment, human-readable changelog should be available soon. In the meantime please refer to **[GitHub commits](https://github.com/JustArchi/ArchiSteamFarm/commits/$(appveyor_repo_tag_name))**.\n\n---\n\nASF is available for free. If you''re grateful for what we''re doing, please consider donating. Developing ASF requires massive amount of time and knowledge, especially when it comes to Steam (and its problems). Even 1$ is highly appreciated and shows that you care!\n\n [](https://www.patreon.com/JustArchi) [](https://www.paypal.me/JustArchi/1usd) [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HD2P2P3WGS5Y4) [](https://blockchain.info/payment_request?address=1Archi6M1r5b41Rvn1SY2FfJAzsrEUT7aT) [](https://steamcommunity.com/tradeoffer/new/?partner=46697991&token=0ix2Ruv_)'
|
||||
auth_token:
|
||||
secure: QC5gIDMvSpd43EG6qW8d1E3ZHiVU4aR7pbKQonXstjj/JtAABf5S1IbtoY4OsnOR
|
||||
artifact: /.*/
|
||||
@@ -62,7 +62,7 @@ notifications:
|
||||
{
|
||||
"avatar_url": "https://www.appveyor.com/assets/img/appveyor-logo-256.png",
|
||||
"username": "AppVeyor",
|
||||
"content": "[{{projectName}}:{{branch}}] {{commitMessage}} - {{committerName}} ({{commitId}}) | **{{status}}** | {{buildUrl}}"
|
||||
"content": "[{{projectName}}:{{branch}}] {{commitMessage}} - {{committerName}} ({{commitId}}) | {{buildUrl}}/artifacts | **{{status}}**"
|
||||
}
|
||||
on_build_success: true
|
||||
on_build_failure: true
|
||||
|
||||
Reference in New Issue
Block a user