mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-18 15:30:30 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7c8b871b3 | ||
|
|
678b32f318 | ||
|
|
62221fd6b8 | ||
|
|
f932be1395 | ||
|
|
d8fd1035c3 | ||
|
|
09e8a52811 | ||
|
|
0b1032199b | ||
|
|
3e5dfb3174 | ||
|
|
4ada8595bd | ||
|
|
bc64c43748 | ||
|
|
f4f7935d4c | ||
|
|
aacc0a1720 | ||
|
|
e5ee909b96 | ||
|
|
f3f444d0bd | ||
|
|
43d18b6d49 | ||
|
|
f24be67c8c | ||
|
|
6ce4f2941b |
@@ -33,6 +33,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.JSON;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using Mono.Unix;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal static class ASF {
|
||||
@@ -210,6 +211,17 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsUnixVersion(version)) {
|
||||
string executable = Path.Combine(targetDirectory, SharedInfo.AssemblyName);
|
||||
if (File.Exists(executable)) {
|
||||
if (UnixFileSystemInfo.TryGetFileSystemEntry(executable, out UnixFileSystemInfo entry)) {
|
||||
if (!entry.FileAccessPermissions.HasFlag(FileAccessPermissions.UserExecute)) {
|
||||
entry.FileAccessPermissions = entry.FileAccessPermissions | FileAccessPermissions.UserExecute;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArchiLogger.LogGenericInfo(Strings.UpdateFinished);
|
||||
await RestartOrExit().ConfigureAwait(false);
|
||||
}
|
||||
@@ -268,6 +280,22 @@ namespace ArchiSteamFarm {
|
||||
Bot.RegisterBot(botName);
|
||||
}
|
||||
|
||||
private static bool IsUnixVersion(string version) {
|
||||
if (string.IsNullOrEmpty(version)) {
|
||||
ArchiLogger.LogNullError(nameof(version));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (version) {
|
||||
case "linux-arm":
|
||||
case "linux-x64":
|
||||
case "osx-x64":
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsValidBotName(string botName) {
|
||||
if (string.IsNullOrEmpty(botName)) {
|
||||
ArchiLogger.LogNullError(nameof(botName));
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||
<AssemblyVersion>3.0.0.7</AssemblyVersion>
|
||||
<FileVersion>3.0.0.7</FileVersion>
|
||||
<AssemblyVersion>3.0.1.0</AssemblyVersion>
|
||||
<FileVersion>3.0.1.0</FileVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ErrorReport>none</ErrorReport>
|
||||
<ApplicationIcon>ASF.ico</ApplicationIcon>
|
||||
@@ -28,9 +28,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.5.2-beta3" />
|
||||
<PackageReference Include="Humanizer" Version="2.2.0" />
|
||||
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0-beta1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="NLog" Version="5.0.0-beta09" />
|
||||
<PackageReference Include="SteamKit2" Version="2.0.0-Alpha5" />
|
||||
<PackageReference Include="SteamKit2" Version="2.0.0-Alpha6" />
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0-preview2-25405-01" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -50,12 +50,11 @@ namespace ArchiSteamFarm {
|
||||
private const ushort MaxSteamMessageLength = 2048;
|
||||
private const byte MaxTwoFactorCodeFailures = 3;
|
||||
private const byte MinHeartBeatTTL = GlobalConfig.DefaultConnectionTimeout; // Assume client is responsive for at least that amount of seconds
|
||||
private const byte PICSCooldownInMiliseconds = 200; // We might need to tune this further
|
||||
|
||||
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;
|
||||
@@ -74,16 +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 PICSSemaphore = 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;
|
||||
@@ -361,10 +360,7 @@ namespace ArchiSteamFarm {
|
||||
ArchiLogger.LogGenericException(e);
|
||||
return (0, DateTime.MinValue);
|
||||
} finally {
|
||||
Task.Run(async () => {
|
||||
await Task.Delay(PICSCooldownInMiliseconds).ConfigureAwait(false);
|
||||
PICSSemaphore.Release();
|
||||
}).Forget();
|
||||
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
|
||||
@@ -471,10 +467,7 @@ namespace ArchiSteamFarm {
|
||||
ArchiLogger.LogGenericException(e);
|
||||
return null;
|
||||
} finally {
|
||||
Task.Run(async () => {
|
||||
await Task.Delay(PICSCooldownInMiliseconds).ConfigureAwait(false);
|
||||
PICSSemaphore.Release();
|
||||
}).Forget();
|
||||
PICSSemaphore.Release();
|
||||
}
|
||||
|
||||
Dictionary<uint, HashSet<uint>> result = new Dictionary<uint, HashSet<uint>>();
|
||||
@@ -1141,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;
|
||||
|
||||
@@ -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());
|
||||
@@ -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;
|
||||
@@ -689,8 +691,7 @@ namespace ArchiSteamFarm {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -218,7 +218,7 @@
|
||||
<value>无账号正在运行,即将退出...</value>
|
||||
</data>
|
||||
<data name="RefreshingOurSession" xml:space="preserve">
|
||||
<value>刷新会话 !</value>
|
||||
<value>正在刷新会话!</value>
|
||||
</data>
|
||||
<data name="RejectingTrade" xml:space="preserve">
|
||||
<value>拒绝交易︰ {0}</value>
|
||||
@@ -341,10 +341,10 @@
|
||||
<comment>{0} will be replaced by the name of chosen idling algorithm</comment>
|
||||
</data>
|
||||
<data name="Done" xml:space="preserve">
|
||||
<value>完成。</value>
|
||||
<value>完成!</value>
|
||||
</data>
|
||||
<data name="GamesToIdle" xml:space="preserve">
|
||||
<value>共有{0} 个游戏(共计{1} 张卡) 等待挂卡(~还剩{2})...</value>
|
||||
<value>共有 {0} 个游戏(共计 {1} 张卡) 等待挂卡(~还剩{2})...</value>
|
||||
<comment>{0} will be replaced by number of games, {1} will be replaced by number of cards, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes")</comment>
|
||||
</data>
|
||||
<data name="IdlingFinished" xml:space="preserve">
|
||||
@@ -363,13 +363,13 @@
|
||||
<comment>{0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to idle</comment>
|
||||
</data>
|
||||
<data name="IdlingStopped" xml:space="preserve">
|
||||
<value>挂卡已停止</value>
|
||||
<value>已停止挂卡!</value>
|
||||
</data>
|
||||
<data name="IgnoredStickyPauseEnabled" xml:space="preserve">
|
||||
<value>请求已忽略,因为强制暂停已开启</value>
|
||||
</data>
|
||||
<data name="NothingToIdle" xml:space="preserve">
|
||||
<value>该账户已经无卡可挂</value>
|
||||
<value>该账户已经无卡可挂!</value>
|
||||
</data>
|
||||
<data name="NowIdling" xml:space="preserve">
|
||||
<value>正在挂卡︰{0} ({1})</value>
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -53,6 +53,10 @@ namespace ArchiSteamFarm {
|
||||
internal static WebBrowser WebBrowser { get; private set; }
|
||||
|
||||
private static readonly object ConsoleLock = new object();
|
||||
|
||||
// We need to keep this one assigned and not calculated on-demand
|
||||
private static readonly string ProcessFileName = Process.GetCurrentProcess().MainModule.FileName;
|
||||
|
||||
private static readonly ManualResetEventSlim ShutdownResetEvent = new ManualResetEventSlim(false);
|
||||
|
||||
private static bool ShutdownSequenceInitialized;
|
||||
@@ -124,13 +128,11 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
string executable = Process.GetCurrentProcess().MainModule.FileName;
|
||||
string executableName = Path.GetFileNameWithoutExtension(executable);
|
||||
|
||||
string executableName = Path.GetFileNameWithoutExtension(ProcessFileName);
|
||||
IEnumerable<string> arguments = Environment.GetCommandLineArgs().Skip(executableName.Equals(SharedInfo.AssemblyName) ? 1 : 0);
|
||||
|
||||
try {
|
||||
Process.Start(executable, string.Join(" ", arguments));
|
||||
Process.Start(ProcessFileName, string.Join(" ", arguments));
|
||||
} catch (Exception e) {
|
||||
ASF.ArchiLogger.LogGenericException(e);
|
||||
}
|
||||
@@ -155,7 +157,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
private static async Task InitASF(string[] args) {
|
||||
ASF.ArchiLogger.LogGenericInfo("ASF V" + SharedInfo.Version);
|
||||
ASF.ArchiLogger.LogGenericInfo("ASF V" + SharedInfo.Version + " (" + SharedInfo.ModuleVersion + ")");
|
||||
|
||||
await InitGlobalConfigAndLanguage().ConfigureAwait(false);
|
||||
await InitGlobalDatabaseAndServices().ConfigureAwait(false);
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace ArchiSteamFarm {
|
||||
internal const string UpdateDirectory = "_old";
|
||||
internal const string VersionFile = AssemblyName + ".version";
|
||||
|
||||
internal static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;
|
||||
internal static Guid ModuleVersion => Assembly.GetEntryAssembly().ManifestModule.ModuleVersionId;
|
||||
internal static Version Version => Assembly.GetEntryAssembly().GetName().Version;
|
||||
}
|
||||
}
|
||||
@@ -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,11 +535,19 @@ 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);
|
||||
}
|
||||
|
||||
ASF.ArchiLogger.LogGenericDebug("Asked for <" + requestUri + ">, got unsafely redirected to <" + responseMessage.Headers.Location + ">, resolved URI to: <" + redirectUri + ">");
|
||||
} else {
|
||||
if (!Debugging.IsDebugBuild) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user