mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-25 10:46:48 +00:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac007a7d12 | ||
|
|
d5c55407b3 | ||
|
|
42ad54e3df | ||
|
|
d13da54dab | ||
|
|
21efa0371a | ||
|
|
ebf91cf98c | ||
|
|
4f4cf083ad | ||
|
|
a6a1781ab9 | ||
|
|
3f3a00e457 | ||
|
|
0382663191 | ||
|
|
f838b3389b | ||
|
|
73885f117a | ||
|
|
0bde6ed45f | ||
|
|
f550d65897 | ||
|
|
5246b2b82d | ||
|
|
6e99d5beed | ||
|
|
69936d55b6 | ||
|
|
d191820317 | ||
|
|
c144c1761d | ||
|
|
267f7b1e53 | ||
|
|
c45364ef99 | ||
|
|
a2542a8c12 | ||
|
|
2e2fb1828d | ||
|
|
f007f30c0d | ||
|
|
74881094ab | ||
|
|
ee98282475 | ||
|
|
e49ec14c41 | ||
|
|
56f4604819 | ||
|
|
56eb5ba8a8 | ||
|
|
8206dff4c1 | ||
|
|
f7426a4439 | ||
|
|
c478ca691d | ||
|
|
a3ff3cafa4 | ||
|
|
313d353ae5 | ||
|
|
dabf391576 | ||
|
|
8ad552b0da | ||
|
|
c16c25da77 | ||
|
|
aa1fc829b7 | ||
|
|
e5eea110f1 | ||
|
|
2e5828779f | ||
|
|
cc2e73ae5a | ||
|
|
b89840f103 | ||
|
|
12b32472ba | ||
|
|
86ac2ade1e | ||
|
|
a180c46b5d | ||
|
|
34555f8bb5 |
2
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -40,7 +40,7 @@ Feel free to remove our notice and fill the template below with your details.
|
||||
|
||||
### Full log.txt recorded during reproducing the problem
|
||||
|
||||
```
|
||||
```text
|
||||
Paste here, in-between triple backtick tags
|
||||
|
||||
Ensure that your log is complete and was NOT recorded in Debug mode, as debug log may contain sensitive information that should not be shared publicly, as per our wiki statement. Standard ASF log does not include sensitive information.
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -6,7 +6,7 @@ contact_links:
|
||||
- name: Localization improvement
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Localization
|
||||
about: Please use our crowdin platform.
|
||||
- name: Questions and technical issues
|
||||
- name: Support question or technical issue
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/blob/master/SUPPORT.md
|
||||
about: Please review our support guidelines.
|
||||
- name: Negative feedback, complaints and demands
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
||||
run: npm ci --no-progress --prefix ASF-ui
|
||||
|
||||
- name: Build ASF-ui
|
||||
run: npm run-script build:ci --no-progress --prefix ASF-ui
|
||||
run: npm run-script deploy --no-progress --prefix ASF-ui
|
||||
|
||||
- name: Build ArchiSteamFarm
|
||||
run: dotnet build ArchiSteamFarm -c "${{ env.CONFIGURATION }}" -p:UseAppHost=false --nologo
|
||||
|
||||
Submodule ASF-WebConfigGenerator updated: a8b5e7b653...c62b75a7a8
2
ASF-ui
2
ASF-ui
Submodule ASF-ui updated: 5400bcdd1f...e3da5e5f7a
@@ -26,6 +26,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Json;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
|
||||
@@ -38,6 +39,10 @@ namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin {
|
||||
// This will keep your code compact, efficient and less dependent. You can always add additional interfaces when you'll need them, this example project will inherit quite a bit of them to show you potential usage
|
||||
// ReSharper disable once UnusedType.Global - this is example plugin class that isn't used in our main code
|
||||
internal sealed class ExamplePlugin : IASF, IBot, IBotCommand, IBotConnection, IBotFriendRequest, IBotMessage, IBotModules, IBotTradeOffer {
|
||||
// Plugins can expose custom properties for our GET /Api/Plugins API call, simply annotate them with [JsonProperty] (or keep public)
|
||||
[JsonProperty]
|
||||
public readonly bool CustomIsEnabledField = true;
|
||||
|
||||
// This is used for identification purposes, typically you want to use a friendly name of your plugin here, such as the name of your main class
|
||||
// Please note that this property can have direct dependencies only on structures that were initialized by the constructor, as it's possible to be called before OnLoaded() takes place
|
||||
public string Name => nameof(ExamplePlugin);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2020 Ł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 Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
public sealed class GlobalConfigExtension {
|
||||
[JsonProperty]
|
||||
public readonly bool SteamTokenDumperPluginEnabled;
|
||||
|
||||
[JsonConstructor]
|
||||
internal GlobalConfigExtension() { }
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
internal static class SharedInfo {
|
||||
internal const byte ApiVersion = 1;
|
||||
internal const byte AppInfosPerSingleRequest = byte.MaxValue;
|
||||
internal const string ConfigurationPropertyEnabled = nameof(SteamTokenDumperPlugin) + "Enabled";
|
||||
internal const byte MaximumHoursBetweenRefresh = 8; // Per single bot account, makes sense to be 2 or 3 times less than MinimumHoursBetweenUploads
|
||||
internal const byte MaximumMinutesBeforeFirstUpload = 60; // Must be greater or equal to MinimumMinutesBeforeFirstUpload
|
||||
internal const byte MinimumHoursBetweenUploads = 24;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2020 Ł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.Net;
|
||||
using ArchiSteamFarm.IPC.Controllers.Api;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
[Route("Api/SteamTokenDumperPlugin")]
|
||||
public sealed class SteamTokenDumperController : ArchiController {
|
||||
[HttpGet(nameof(GlobalConfigExtension))]
|
||||
[ProducesResponseType(typeof(GlobalConfigExtension), (int) HttpStatusCode.OK)]
|
||||
[SwaggerOperation(Tags = new[] { nameof(GlobalConfigExtension) })]
|
||||
public ActionResult<GlobalConfigExtension> Get() => Ok(new GlobalConfigExtension());
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ using System.Threading.Tasks;
|
||||
using ArchiSteamFarm.Localization;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SteamKit2;
|
||||
|
||||
@@ -43,10 +44,14 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
private static readonly Timer SubmissionTimer = new Timer(async e => await SubmitData().ConfigureAwait(false));
|
||||
|
||||
private static GlobalCache GlobalCache;
|
||||
|
||||
[JsonProperty]
|
||||
private static bool IsEnabled;
|
||||
|
||||
[JsonProperty]
|
||||
public override string Name => nameof(SteamTokenDumperPlugin);
|
||||
|
||||
[JsonProperty]
|
||||
public override Version Version => typeof(SteamTokenDumperPlugin).Assembly.GetName().Version ?? throw new ArgumentNullException(nameof(Version));
|
||||
|
||||
public Task<uint> GetPreferredChangeNumberToStartFrom() => Task.FromResult(IsEnabled ? GlobalCache?.LastChangeNumber ?? 0 : 0);
|
||||
@@ -63,7 +68,7 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
if (additionalConfigProperties != null) {
|
||||
foreach ((string configProperty, JToken configValue) in additionalConfigProperties) {
|
||||
try {
|
||||
if (configProperty == SharedInfo.ConfigurationPropertyEnabled) {
|
||||
if (configProperty == nameof(GlobalConfigExtension.SteamTokenDumperPluginEnabled)) {
|
||||
enabled = configValue.Value<bool>();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -262,6 +267,10 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bot.IsConnectedAndLoggedOn) {
|
||||
return;
|
||||
}
|
||||
|
||||
bot.ArchiLogger.LogGenericInfo($"Retrieving {appIDsThisRound.Count} app access tokens...");
|
||||
|
||||
SteamApps.PICSTokensCallback response;
|
||||
@@ -274,6 +283,12 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
return;
|
||||
}
|
||||
|
||||
if (response == null) {
|
||||
bot.ArchiLogger.LogGenericWarning(string.Format(Strings.WarningFailedWithError, nameof(response)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bot.ArchiLogger.LogGenericInfo($"Finished retrieving {appIDsThisRound.Count} app access tokens.");
|
||||
|
||||
appIDsThisRound.Clear();
|
||||
@@ -297,6 +312,10 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!bot.IsConnectedAndLoggedOn) {
|
||||
return;
|
||||
}
|
||||
|
||||
bot.ArchiLogger.LogGenericInfo($"Retrieving {appIDsThisRound.Count} app infos...");
|
||||
|
||||
AsyncJobMultiple<SteamApps.PICSProductInfoCallback>.ResultSet response;
|
||||
@@ -342,7 +361,15 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper {
|
||||
if (depotTasks.Count > 0) {
|
||||
bot.ArchiLogger.LogGenericInfo($"Retrieving {depotTasks.Count} depot keys...");
|
||||
|
||||
SteamApps.DepotKeyCallback[] results = await Task.WhenAll(depotTasks).ConfigureAwait(false);
|
||||
SteamApps.DepotKeyCallback[] results;
|
||||
|
||||
try {
|
||||
results = await Task.WhenAll(depotTasks).ConfigureAwait(false);
|
||||
} catch (Exception e) {
|
||||
bot.ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bot.ArchiLogger.LogGenericInfo($"Finished retrieving {depotTasks.Count} depot keys.");
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
<PackageReference Include="NLog" Version="4.7.2" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.2" />
|
||||
<PackageReference Include="SteamKit2" Version="2.3.0-beta.2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.4.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="5.4.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="5.4.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="5.5.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="5.5.1" />
|
||||
<PackageReference Include="System.Composition" Version="1.4.1" />
|
||||
<PackageReference Include="System.Linq.Async" Version="4.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -50,13 +50,13 @@ namespace ArchiSteamFarm {
|
||||
[PublicAPI]
|
||||
public const string SteamStoreURL = "https://" + SteamStoreHost;
|
||||
|
||||
internal const ushort MaxItemsInSingleInventoryRequest = 5000;
|
||||
|
||||
private const string IEconService = "IEconService";
|
||||
private const string IPlayerService = "IPlayerService";
|
||||
private const string ISteamApps = "ISteamApps";
|
||||
private const string ISteamUserAuth = "ISteamUserAuth";
|
||||
private const string ITwoFactorService = "ITwoFactorService";
|
||||
private const ushort MaxItemsInSingleInventoryRequest = 5000;
|
||||
private const byte MinSessionValidityInSeconds = GlobalConfig.DefaultConnectionTimeout / 6;
|
||||
private const string SteamCommunityHost = "steamcommunity.com";
|
||||
private const string SteamHelpHost = "help.steampowered.com";
|
||||
private const string SteamStoreHost = "store.steampowered.com";
|
||||
@@ -2392,14 +2392,16 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
private async Task<bool?> IsSessionExpired() {
|
||||
if (DateTime.UtcNow < LastSessionCheck.AddSeconds(MinSessionValidityInSeconds)) {
|
||||
DateTime triggeredAt = DateTime.UtcNow;
|
||||
|
||||
if (triggeredAt <= LastSessionCheck) {
|
||||
return LastSessionCheck != LastSessionRefresh;
|
||||
}
|
||||
|
||||
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
if (DateTime.UtcNow < LastSessionCheck.AddSeconds(MinSessionValidityInSeconds)) {
|
||||
if (triggeredAt <= LastSessionCheck) {
|
||||
return LastSessionCheck != LastSessionRefresh;
|
||||
}
|
||||
|
||||
@@ -2521,15 +2523,15 @@ namespace ArchiSteamFarm {
|
||||
|
||||
DateTime triggeredAt = DateTime.UtcNow;
|
||||
|
||||
if (triggeredAt < LastSessionRefresh.AddSeconds(MinSessionValidityInSeconds)) {
|
||||
return true;
|
||||
if (triggeredAt <= LastSessionCheck) {
|
||||
return LastSessionCheck == LastSessionRefresh;
|
||||
}
|
||||
|
||||
await SessionSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try {
|
||||
if (triggeredAt < LastSessionRefresh.AddSeconds(MinSessionValidityInSeconds)) {
|
||||
return true;
|
||||
if (triggeredAt <= LastSessionCheck) {
|
||||
return LastSessionCheck == LastSessionRefresh;
|
||||
}
|
||||
|
||||
if (!Bot.IsConnectedAndLoggedOn) {
|
||||
@@ -2539,10 +2541,14 @@ namespace ArchiSteamFarm {
|
||||
Bot.ArchiLogger.LogGenericInfo(Strings.RefreshingOurSession);
|
||||
bool result = await Bot.RefreshSession().ConfigureAwait(false);
|
||||
|
||||
DateTime now = DateTime.UtcNow;
|
||||
|
||||
if (result) {
|
||||
LastSessionCheck = LastSessionRefresh = DateTime.UtcNow;
|
||||
LastSessionRefresh = now;
|
||||
}
|
||||
|
||||
LastSessionCheck = now;
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
SessionSemaphore.Release();
|
||||
@@ -2620,7 +2626,7 @@ namespace ArchiSteamFarm {
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
IElement htmlNode = htmlDocument.SelectSingleNode("//div[@data-component='ProfilePrivacySettings']/@data-privacysettings");
|
||||
IElement htmlNode = htmlDocument.SelectSingleNode("//div[@id='profile_edit_config']");
|
||||
|
||||
if (htmlNode == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(htmlNode));
|
||||
@@ -2628,7 +2634,7 @@ namespace ArchiSteamFarm {
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
string json = htmlNode.GetAttributeValue("data-privacysettings");
|
||||
string json = htmlNode.GetAttributeValue("data-profile-edit");
|
||||
|
||||
if (string.IsNullOrEmpty(json)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(json));
|
||||
@@ -2639,40 +2645,40 @@ namespace ArchiSteamFarm {
|
||||
// This json is encoded as html attribute, don't forget to decode it
|
||||
json = WebUtility.HtmlDecode(json);
|
||||
|
||||
Steam.UserPrivacy userPrivacy;
|
||||
Steam.ProfileEditData profileEditData;
|
||||
|
||||
try {
|
||||
userPrivacy = JsonConvert.DeserializeObject<Steam.UserPrivacy>(json);
|
||||
profileEditData = JsonConvert.DeserializeObject<Steam.ProfileEditData>(json);
|
||||
} catch (JsonException e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
if (userPrivacy == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(userPrivacy));
|
||||
if (profileEditData == null) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(profileEditData));
|
||||
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
switch (userPrivacy.Settings.Profile) {
|
||||
switch (profileEditData.Privacy.Settings.Profile) {
|
||||
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.FriendsOnly:
|
||||
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private:
|
||||
return (true, false);
|
||||
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Public:
|
||||
switch (userPrivacy.Settings.Inventory) {
|
||||
switch (profileEditData.Privacy.Settings.Inventory) {
|
||||
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.FriendsOnly:
|
||||
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Private:
|
||||
return (true, false);
|
||||
case Steam.UserPrivacy.PrivacySettings.EPrivacySetting.Public:
|
||||
return (true, true);
|
||||
default:
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(userPrivacy.Settings.Inventory), userPrivacy.Settings.Inventory));
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(profileEditData.Privacy.Settings.Inventory), profileEditData.Privacy.Settings.Inventory));
|
||||
|
||||
return (false, false);
|
||||
}
|
||||
default:
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(userPrivacy.Settings.Profile), userPrivacy.Settings.Profile));
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(profileEditData.Privacy.Settings.Profile), profileEditData.Privacy.Settings.Profile));
|
||||
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -122,8 +123,6 @@ namespace ArchiSteamFarm {
|
||||
internal readonly ArchiHandler ArchiHandler;
|
||||
internal readonly BotDatabase BotDatabase;
|
||||
|
||||
internal readonly ConcurrentDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)> OwnedPackageIDs = new ConcurrentDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)>();
|
||||
|
||||
internal bool CanReceiveSteamCards => !IsAccountLimited && !IsAccountLocked;
|
||||
internal bool IsAccountLimited => AccountFlags.HasFlag(EAccountFlags.LimitedUser) || AccountFlags.HasFlag(EAccountFlags.LimitedUserForce);
|
||||
internal bool IsAccountLocked => AccountFlags.HasFlag(EAccountFlags.Lockdown);
|
||||
@@ -195,6 +194,7 @@ namespace ArchiSteamFarm {
|
||||
[PublicAPI]
|
||||
public ECurrencyCode WalletCurrency { get; private set; }
|
||||
|
||||
internal ImmutableDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)> OwnedPackageIDs { get; private set; } = ImmutableDictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)>.Empty;
|
||||
internal bool PlayingBlocked { get; private set; }
|
||||
internal bool PlayingWasBlocked { get; private set; }
|
||||
|
||||
@@ -2160,7 +2160,6 @@ namespace ArchiSteamFarm {
|
||||
|
||||
ArchiLogger.LogGenericInfo(Strings.BotDisconnected);
|
||||
|
||||
OwnedPackageIDs.Clear();
|
||||
PastNotifications.Clear();
|
||||
|
||||
Actions.OnDisconnected();
|
||||
@@ -2384,16 +2383,21 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
|
||||
bool initialLogin = OwnedPackageIDs.Count == 0;
|
||||
if (callback.LicenseList.Count == 0) {
|
||||
ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsEmpty, nameof(callback.LicenseList)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Commands.OnNewLicenseList();
|
||||
OwnedPackageIDs.Clear();
|
||||
|
||||
Dictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)> ownedPackageIDs = new Dictionary<uint, (EPaymentMethod PaymentMethod, DateTime TimeCreated)>();
|
||||
|
||||
Dictionary<uint, ulong> packageAccessTokens = new Dictionary<uint, ulong>();
|
||||
Dictionary<uint, uint> packagesToRefresh = new Dictionary<uint, uint>();
|
||||
|
||||
foreach (SteamApps.LicenseListCallback.License license in callback.LicenseList.GroupBy(license => license.PackageID, (packageID, licenses) => licenses.OrderByDescending(license => license.TimeCreated).First())) {
|
||||
OwnedPackageIDs[license.PackageID] = (license.PaymentMethod, license.TimeCreated);
|
||||
ownedPackageIDs[license.PackageID] = (license.PaymentMethod, license.TimeCreated);
|
||||
|
||||
if (!ASF.GlobalDatabase.PackageAccessTokensReadOnly.TryGetValue(license.PackageID, out ulong packageAccessToken) || (packageAccessToken != license.AccessToken)) {
|
||||
packageAccessTokens[license.PackageID] = license.AccessToken;
|
||||
@@ -2405,6 +2409,8 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
OwnedPackageIDs = ownedPackageIDs.ToImmutableDictionary();
|
||||
|
||||
if (packageAccessTokens.Count > 0) {
|
||||
ASF.GlobalDatabase.RefreshPackageAccessTokens(packageAccessTokens);
|
||||
}
|
||||
@@ -2415,11 +2421,6 @@ namespace ArchiSteamFarm {
|
||||
ArchiLogger.LogGenericTrace(Strings.Done);
|
||||
}
|
||||
|
||||
if (initialLogin && CardsFarmer.Paused) {
|
||||
// Emit initial game playing status in this case
|
||||
await ResetGamesPlayed().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await CardsFarmer.OnNewGameAdded().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
@@ -2623,6 +2624,11 @@ namespace ArchiSteamFarm {
|
||||
);
|
||||
}
|
||||
|
||||
if (CardsFarmer.Paused) {
|
||||
// Emit initial game playing status in this case
|
||||
Utilities.InBackground(ResetGamesPlayed);
|
||||
}
|
||||
|
||||
SteamPICSChanges.OnBotLoggedOn();
|
||||
|
||||
await PluginsCore.OnBotLoggedOn(this).ConfigureAwait(false);
|
||||
|
||||
@@ -190,8 +190,9 @@ namespace ArchiSteamFarm {
|
||||
internal bool IsSteamLoginSet { get; private set; }
|
||||
internal bool IsSteamParentalCodeSet { get; private set; }
|
||||
internal bool IsSteamPasswordSet { get; private set; }
|
||||
internal bool ShouldSerializeEverything { private get; set; } = true;
|
||||
internal bool ShouldSerializeDefaultValues { private get; set; } = true;
|
||||
internal bool ShouldSerializeHelperProperties { private get; set; } = true;
|
||||
internal bool ShouldSerializeSensitiveDetails { private get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal string SteamLogin {
|
||||
@@ -226,7 +227,6 @@ namespace ArchiSteamFarm {
|
||||
private string BackingSteamLogin = DefaultSteamLogin;
|
||||
private string BackingSteamParentalCode = DefaultSteamParentalCode;
|
||||
private string BackingSteamPassword = DefaultSteamPassword;
|
||||
private bool ShouldSerializeSensitiveDetails = true;
|
||||
|
||||
[JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(SteamMasterClanID), Required = Required.DisallowNull)]
|
||||
[JetBrains.Annotations.NotNull]
|
||||
@@ -345,9 +345,6 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
botConfig.ShouldSerializeEverything = false;
|
||||
botConfig.ShouldSerializeSensitiveDetails = false;
|
||||
|
||||
return botConfig;
|
||||
}
|
||||
|
||||
@@ -442,36 +439,36 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
public bool ShouldSerializeAcceptGifts() => ShouldSerializeEverything || (AcceptGifts != DefaultAcceptGifts);
|
||||
public bool ShouldSerializeAutoSteamSaleEvent() => ShouldSerializeEverything || (AutoSteamSaleEvent != DefaultAutoSteamSaleEvent);
|
||||
public bool ShouldSerializeBotBehaviour() => ShouldSerializeEverything || (BotBehaviour != DefaultBotBehaviour);
|
||||
public bool ShouldSerializeCustomGamePlayedWhileFarming() => ShouldSerializeEverything || (CustomGamePlayedWhileFarming != DefaultCustomGamePlayedWhileFarming);
|
||||
public bool ShouldSerializeCustomGamePlayedWhileIdle() => ShouldSerializeEverything || (CustomGamePlayedWhileIdle != DefaultCustomGamePlayedWhileIdle);
|
||||
public bool ShouldSerializeEnabled() => ShouldSerializeEverything || (Enabled != DefaultEnabled);
|
||||
public bool ShouldSerializeFarmingOrders() => ShouldSerializeEverything || ((FarmingOrders != DefaultFarmingOrders) && !FarmingOrders.SequenceEqual(DefaultFarmingOrders));
|
||||
public bool ShouldSerializeGamesPlayedWhileIdle() => ShouldSerializeEverything || ((GamesPlayedWhileIdle != DefaultGamesPlayedWhileIdle) && !GamesPlayedWhileIdle.SetEquals(DefaultGamesPlayedWhileIdle));
|
||||
public bool ShouldSerializeHoursUntilCardDrops() => ShouldSerializeEverything || (HoursUntilCardDrops != DefaultHoursUntilCardDrops);
|
||||
public bool ShouldSerializeIdlePriorityQueueOnly() => ShouldSerializeEverything || (IdlePriorityQueueOnly != DefaultIdlePriorityQueueOnly);
|
||||
public bool ShouldSerializeIdleRefundableGames() => ShouldSerializeEverything || (IdleRefundableGames != DefaultIdleRefundableGames);
|
||||
public bool ShouldSerializeLootableTypes() => ShouldSerializeEverything || ((LootableTypes != DefaultLootableTypes) && !LootableTypes.SetEquals(DefaultLootableTypes));
|
||||
public bool ShouldSerializeMatchableTypes() => ShouldSerializeEverything || ((MatchableTypes != DefaultMatchableTypes) && !MatchableTypes.SetEquals(DefaultMatchableTypes));
|
||||
public bool ShouldSerializeOnlineStatus() => ShouldSerializeEverything || (OnlineStatus != DefaultOnlineStatus);
|
||||
public bool ShouldSerializePasswordFormat() => ShouldSerializeEverything || (PasswordFormat != DefaultPasswordFormat);
|
||||
public bool ShouldSerializePaused() => ShouldSerializeEverything || (Paused != DefaultPaused);
|
||||
public bool ShouldSerializeRedeemingPreferences() => ShouldSerializeEverything || (RedeemingPreferences != DefaultRedeemingPreferences);
|
||||
public bool ShouldSerializeSendOnFarmingFinished() => ShouldSerializeEverything || (SendOnFarmingFinished != DefaultSendOnFarmingFinished);
|
||||
public bool ShouldSerializeSendTradePeriod() => ShouldSerializeEverything || (SendTradePeriod != DefaultSendTradePeriod);
|
||||
public bool ShouldSerializeShutdownOnFarmingFinished() => ShouldSerializeEverything || (ShutdownOnFarmingFinished != DefaultShutdownOnFarmingFinished);
|
||||
public bool ShouldSerializeSSteamMasterClanID() => ShouldSerializeEverything || (ShouldSerializeHelperProperties && (SteamMasterClanID != DefaultSteamMasterClanID));
|
||||
public bool ShouldSerializeSteamLogin() => ShouldSerializeSensitiveDetails && (ShouldSerializeEverything || (SteamLogin != DefaultSteamLogin));
|
||||
public bool ShouldSerializeSteamMasterClanID() => ShouldSerializeEverything || (SteamMasterClanID != DefaultSteamMasterClanID);
|
||||
public bool ShouldSerializeSteamParentalCode() => ShouldSerializeSensitiveDetails && (ShouldSerializeEverything || (SteamParentalCode != DefaultSteamParentalCode));
|
||||
public bool ShouldSerializeSteamPassword() => ShouldSerializeSensitiveDetails && (ShouldSerializeEverything || (SteamPassword != DefaultSteamPassword));
|
||||
public bool ShouldSerializeSteamTradeToken() => ShouldSerializeEverything || (SteamTradeToken != DefaultSteamTradeToken);
|
||||
public bool ShouldSerializeSteamUserPermissions() => ShouldSerializeEverything || ((SteamUserPermissions != DefaultSteamUserPermissions) && ((SteamUserPermissions.Count != DefaultSteamUserPermissions.Count) || SteamUserPermissions.Except(DefaultSteamUserPermissions).Any()));
|
||||
public bool ShouldSerializeTradingPreferences() => ShouldSerializeEverything || (TradingPreferences != DefaultTradingPreferences);
|
||||
public bool ShouldSerializeTransferableTypes() => ShouldSerializeEverything || ((TransferableTypes != DefaultTransferableTypes) && !TransferableTypes.SetEquals(DefaultTransferableTypes));
|
||||
public bool ShouldSerializeUseLoginKeys() => ShouldSerializeEverything || (UseLoginKeys != DefaultUseLoginKeys);
|
||||
public bool ShouldSerializeAcceptGifts() => ShouldSerializeDefaultValues || (AcceptGifts != DefaultAcceptGifts);
|
||||
public bool ShouldSerializeAutoSteamSaleEvent() => ShouldSerializeDefaultValues || (AutoSteamSaleEvent != DefaultAutoSteamSaleEvent);
|
||||
public bool ShouldSerializeBotBehaviour() => ShouldSerializeDefaultValues || (BotBehaviour != DefaultBotBehaviour);
|
||||
public bool ShouldSerializeCustomGamePlayedWhileFarming() => ShouldSerializeDefaultValues || (CustomGamePlayedWhileFarming != DefaultCustomGamePlayedWhileFarming);
|
||||
public bool ShouldSerializeCustomGamePlayedWhileIdle() => ShouldSerializeDefaultValues || (CustomGamePlayedWhileIdle != DefaultCustomGamePlayedWhileIdle);
|
||||
public bool ShouldSerializeEnabled() => ShouldSerializeDefaultValues || (Enabled != DefaultEnabled);
|
||||
public bool ShouldSerializeFarmingOrders() => ShouldSerializeDefaultValues || ((FarmingOrders != DefaultFarmingOrders) && !FarmingOrders.SequenceEqual(DefaultFarmingOrders));
|
||||
public bool ShouldSerializeGamesPlayedWhileIdle() => ShouldSerializeDefaultValues || ((GamesPlayedWhileIdle != DefaultGamesPlayedWhileIdle) && !GamesPlayedWhileIdle.SetEquals(DefaultGamesPlayedWhileIdle));
|
||||
public bool ShouldSerializeHoursUntilCardDrops() => ShouldSerializeDefaultValues || (HoursUntilCardDrops != DefaultHoursUntilCardDrops);
|
||||
public bool ShouldSerializeIdlePriorityQueueOnly() => ShouldSerializeDefaultValues || (IdlePriorityQueueOnly != DefaultIdlePriorityQueueOnly);
|
||||
public bool ShouldSerializeIdleRefundableGames() => ShouldSerializeDefaultValues || (IdleRefundableGames != DefaultIdleRefundableGames);
|
||||
public bool ShouldSerializeLootableTypes() => ShouldSerializeDefaultValues || ((LootableTypes != DefaultLootableTypes) && !LootableTypes.SetEquals(DefaultLootableTypes));
|
||||
public bool ShouldSerializeMatchableTypes() => ShouldSerializeDefaultValues || ((MatchableTypes != DefaultMatchableTypes) && !MatchableTypes.SetEquals(DefaultMatchableTypes));
|
||||
public bool ShouldSerializeOnlineStatus() => ShouldSerializeDefaultValues || (OnlineStatus != DefaultOnlineStatus);
|
||||
public bool ShouldSerializePasswordFormat() => ShouldSerializeDefaultValues || (PasswordFormat != DefaultPasswordFormat);
|
||||
public bool ShouldSerializePaused() => ShouldSerializeDefaultValues || (Paused != DefaultPaused);
|
||||
public bool ShouldSerializeRedeemingPreferences() => ShouldSerializeDefaultValues || (RedeemingPreferences != DefaultRedeemingPreferences);
|
||||
public bool ShouldSerializeSendOnFarmingFinished() => ShouldSerializeDefaultValues || (SendOnFarmingFinished != DefaultSendOnFarmingFinished);
|
||||
public bool ShouldSerializeSendTradePeriod() => ShouldSerializeDefaultValues || (SendTradePeriod != DefaultSendTradePeriod);
|
||||
public bool ShouldSerializeShutdownOnFarmingFinished() => ShouldSerializeDefaultValues || (ShutdownOnFarmingFinished != DefaultShutdownOnFarmingFinished);
|
||||
public bool ShouldSerializeSSteamMasterClanID() => ShouldSerializeDefaultValues || (ShouldSerializeHelperProperties && (SteamMasterClanID != DefaultSteamMasterClanID));
|
||||
public bool ShouldSerializeSteamLogin() => ShouldSerializeSensitiveDetails && (ShouldSerializeDefaultValues || (SteamLogin != DefaultSteamLogin));
|
||||
public bool ShouldSerializeSteamMasterClanID() => ShouldSerializeDefaultValues || (SteamMasterClanID != DefaultSteamMasterClanID);
|
||||
public bool ShouldSerializeSteamParentalCode() => ShouldSerializeSensitiveDetails && (ShouldSerializeDefaultValues || (SteamParentalCode != DefaultSteamParentalCode));
|
||||
public bool ShouldSerializeSteamPassword() => ShouldSerializeSensitiveDetails && (ShouldSerializeDefaultValues || (SteamPassword != DefaultSteamPassword));
|
||||
public bool ShouldSerializeSteamTradeToken() => ShouldSerializeDefaultValues || (SteamTradeToken != DefaultSteamTradeToken);
|
||||
public bool ShouldSerializeSteamUserPermissions() => ShouldSerializeDefaultValues || ((SteamUserPermissions != DefaultSteamUserPermissions) && ((SteamUserPermissions.Count != DefaultSteamUserPermissions.Count) || SteamUserPermissions.Except(DefaultSteamUserPermissions).Any()));
|
||||
public bool ShouldSerializeTradingPreferences() => ShouldSerializeDefaultValues || (TradingPreferences != DefaultTradingPreferences);
|
||||
public bool ShouldSerializeTransferableTypes() => ShouldSerializeDefaultValues || ((TransferableTypes != DefaultTransferableTypes) && !TransferableTypes.SetEquals(DefaultTransferableTypes));
|
||||
public bool ShouldSerializeUseLoginKeys() => ShouldSerializeDefaultValues || (UseLoginKeys != DefaultUseLoginKeys);
|
||||
|
||||
// ReSharper restore UnusedMember.Global
|
||||
}
|
||||
|
||||
@@ -36,12 +36,12 @@ using SteamKit2;
|
||||
namespace ArchiSteamFarm {
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
public sealed class GlobalConfig {
|
||||
internal const byte DefaultConnectionTimeout = 90;
|
||||
internal const byte DefaultLoginLimiterDelay = 10;
|
||||
|
||||
private const bool DefaultAutoRestart = true;
|
||||
private const string DefaultCommandPrefix = "!";
|
||||
private const byte DefaultConfirmationsLimiterDelay = 10;
|
||||
private const byte DefaultConnectionTimeout = 90;
|
||||
private const string DefaultCurrentCulture = null;
|
||||
private const bool DefaultDebug = false;
|
||||
private const byte DefaultFarmingDelay = 15;
|
||||
@@ -204,8 +204,9 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
internal bool IsWebProxyPasswordSet { get; private set; }
|
||||
internal bool ShouldSerializeEverything { private get; set; } = true;
|
||||
internal bool ShouldSerializeDefaultValues { private get; set; } = true;
|
||||
internal bool ShouldSerializeHelperProperties { private get; set; } = true;
|
||||
internal bool ShouldSerializeSensitiveDetails { private get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
internal string WebProxyPassword {
|
||||
@@ -219,7 +220,6 @@ namespace ArchiSteamFarm {
|
||||
|
||||
private WebProxy BackingWebProxy;
|
||||
private string BackingWebProxyPassword = DefaultWebProxyPassword;
|
||||
private bool ShouldSerializeSensitiveDetails = true;
|
||||
|
||||
[JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(SteamOwnerID), Required = Required.DisallowNull)]
|
||||
[JetBrains.Annotations.NotNull]
|
||||
@@ -238,7 +238,7 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
private GlobalConfig() { }
|
||||
internal GlobalConfig() { }
|
||||
|
||||
internal (bool Valid, string ErrorMessage) CheckValidation() {
|
||||
if (ConnectionTimeout == 0) {
|
||||
@@ -272,13 +272,6 @@ namespace ArchiSteamFarm {
|
||||
return Enum.IsDefined(typeof(EUpdateChannel), UpdateChannel) ? (true, null) : (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(UpdateChannel), UpdateChannel));
|
||||
}
|
||||
|
||||
[JetBrains.Annotations.NotNull]
|
||||
internal static GlobalConfig Create() =>
|
||||
new GlobalConfig {
|
||||
ShouldSerializeEverything = false,
|
||||
ShouldSerializeSensitiveDetails = false
|
||||
};
|
||||
|
||||
[ItemCanBeNull]
|
||||
internal static async Task<GlobalConfig> Load(string filePath) {
|
||||
if (string.IsNullOrEmpty(filePath)) {
|
||||
@@ -323,9 +316,6 @@ namespace ArchiSteamFarm {
|
||||
return null;
|
||||
}
|
||||
|
||||
globalConfig.ShouldSerializeEverything = false;
|
||||
globalConfig.ShouldSerializeSensitiveDetails = false;
|
||||
|
||||
return globalConfig;
|
||||
}
|
||||
|
||||
@@ -374,35 +364,35 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
public bool ShouldSerializeAutoRestart() => ShouldSerializeEverything || (AutoRestart != DefaultAutoRestart);
|
||||
public bool ShouldSerializeBlacklist() => ShouldSerializeEverything || ((Blacklist != DefaultBlacklist) && !Blacklist.SetEquals(DefaultBlacklist));
|
||||
public bool ShouldSerializeCommandPrefix() => ShouldSerializeEverything || (CommandPrefix != DefaultCommandPrefix);
|
||||
public bool ShouldSerializeConfirmationsLimiterDelay() => ShouldSerializeEverything || (ConfirmationsLimiterDelay != DefaultConfirmationsLimiterDelay);
|
||||
public bool ShouldSerializeConnectionTimeout() => ShouldSerializeEverything || (ConnectionTimeout != DefaultConnectionTimeout);
|
||||
public bool ShouldSerializeCurrentCulture() => ShouldSerializeEverything || (CurrentCulture != DefaultCurrentCulture);
|
||||
public bool ShouldSerializeDebug() => ShouldSerializeEverything || (Debug != DefaultDebug);
|
||||
public bool ShouldSerializeFarmingDelay() => ShouldSerializeEverything || (FarmingDelay != DefaultFarmingDelay);
|
||||
public bool ShouldSerializeGiftsLimiterDelay() => ShouldSerializeEverything || (GiftsLimiterDelay != DefaultGiftsLimiterDelay);
|
||||
public bool ShouldSerializeHeadless() => ShouldSerializeEverything || (Headless != DefaultHeadless);
|
||||
public bool ShouldSerializeIdleFarmingPeriod() => ShouldSerializeEverything || (IdleFarmingPeriod != DefaultIdleFarmingPeriod);
|
||||
public bool ShouldSerializeInventoryLimiterDelay() => ShouldSerializeEverything || (InventoryLimiterDelay != DefaultInventoryLimiterDelay);
|
||||
public bool ShouldSerializeIPC() => ShouldSerializeEverything || (IPC != DefaultIPC);
|
||||
public bool ShouldSerializeIPCPassword() => ShouldSerializeEverything || (IPCPassword != DefaultIPCPassword);
|
||||
public bool ShouldSerializeLoginLimiterDelay() => ShouldSerializeEverything || (LoginLimiterDelay != DefaultLoginLimiterDelay);
|
||||
public bool ShouldSerializeMaxFarmingTime() => ShouldSerializeEverything || (MaxFarmingTime != DefaultMaxFarmingTime);
|
||||
public bool ShouldSerializeMaxTradeHoldDuration() => ShouldSerializeEverything || (MaxTradeHoldDuration != DefaultMaxTradeHoldDuration);
|
||||
public bool ShouldSerializeOptimizationMode() => ShouldSerializeEverything || (OptimizationMode != DefaultOptimizationMode);
|
||||
public bool ShouldSerializeSSteamOwnerID() => ShouldSerializeEverything || (ShouldSerializeHelperProperties && (SteamOwnerID != DefaultSteamOwnerID));
|
||||
public bool ShouldSerializeStatistics() => ShouldSerializeEverything || (Statistics != DefaultStatistics);
|
||||
public bool ShouldSerializeSteamMessagePrefix() => ShouldSerializeEverything || (SteamMessagePrefix != DefaultSteamMessagePrefix);
|
||||
public bool ShouldSerializeSteamOwnerID() => ShouldSerializeEverything || (SteamOwnerID != DefaultSteamOwnerID);
|
||||
public bool ShouldSerializeSteamProtocols() => ShouldSerializeEverything || (SteamProtocols != DefaultSteamProtocols);
|
||||
public bool ShouldSerializeUpdateChannel() => ShouldSerializeEverything || (UpdateChannel != DefaultUpdateChannel);
|
||||
public bool ShouldSerializeUpdatePeriod() => ShouldSerializeEverything || (UpdatePeriod != DefaultUpdatePeriod);
|
||||
public bool ShouldSerializeWebLimiterDelay() => ShouldSerializeEverything || (WebLimiterDelay != DefaultWebLimiterDelay);
|
||||
public bool ShouldSerializeWebProxyPassword() => ShouldSerializeSensitiveDetails && (ShouldSerializeEverything || (WebProxyPassword != DefaultWebProxyPassword));
|
||||
public bool ShouldSerializeWebProxyText() => ShouldSerializeEverything || (WebProxyText != DefaultWebProxyText);
|
||||
public bool ShouldSerializeWebProxyUsername() => ShouldSerializeEverything || (WebProxyUsername != DefaultWebProxyUsername);
|
||||
public bool ShouldSerializeAutoRestart() => ShouldSerializeDefaultValues || (AutoRestart != DefaultAutoRestart);
|
||||
public bool ShouldSerializeBlacklist() => ShouldSerializeDefaultValues || ((Blacklist != DefaultBlacklist) && !Blacklist.SetEquals(DefaultBlacklist));
|
||||
public bool ShouldSerializeCommandPrefix() => ShouldSerializeDefaultValues || (CommandPrefix != DefaultCommandPrefix);
|
||||
public bool ShouldSerializeConfirmationsLimiterDelay() => ShouldSerializeDefaultValues || (ConfirmationsLimiterDelay != DefaultConfirmationsLimiterDelay);
|
||||
public bool ShouldSerializeConnectionTimeout() => ShouldSerializeDefaultValues || (ConnectionTimeout != DefaultConnectionTimeout);
|
||||
public bool ShouldSerializeCurrentCulture() => ShouldSerializeDefaultValues || (CurrentCulture != DefaultCurrentCulture);
|
||||
public bool ShouldSerializeDebug() => ShouldSerializeDefaultValues || (Debug != DefaultDebug);
|
||||
public bool ShouldSerializeFarmingDelay() => ShouldSerializeDefaultValues || (FarmingDelay != DefaultFarmingDelay);
|
||||
public bool ShouldSerializeGiftsLimiterDelay() => ShouldSerializeDefaultValues || (GiftsLimiterDelay != DefaultGiftsLimiterDelay);
|
||||
public bool ShouldSerializeHeadless() => ShouldSerializeDefaultValues || (Headless != DefaultHeadless);
|
||||
public bool ShouldSerializeIdleFarmingPeriod() => ShouldSerializeDefaultValues || (IdleFarmingPeriod != DefaultIdleFarmingPeriod);
|
||||
public bool ShouldSerializeInventoryLimiterDelay() => ShouldSerializeDefaultValues || (InventoryLimiterDelay != DefaultInventoryLimiterDelay);
|
||||
public bool ShouldSerializeIPC() => ShouldSerializeDefaultValues || (IPC != DefaultIPC);
|
||||
public bool ShouldSerializeIPCPassword() => ShouldSerializeDefaultValues || (IPCPassword != DefaultIPCPassword);
|
||||
public bool ShouldSerializeLoginLimiterDelay() => ShouldSerializeDefaultValues || (LoginLimiterDelay != DefaultLoginLimiterDelay);
|
||||
public bool ShouldSerializeMaxFarmingTime() => ShouldSerializeDefaultValues || (MaxFarmingTime != DefaultMaxFarmingTime);
|
||||
public bool ShouldSerializeMaxTradeHoldDuration() => ShouldSerializeDefaultValues || (MaxTradeHoldDuration != DefaultMaxTradeHoldDuration);
|
||||
public bool ShouldSerializeOptimizationMode() => ShouldSerializeDefaultValues || (OptimizationMode != DefaultOptimizationMode);
|
||||
public bool ShouldSerializeSSteamOwnerID() => ShouldSerializeDefaultValues || (ShouldSerializeHelperProperties && (SteamOwnerID != DefaultSteamOwnerID));
|
||||
public bool ShouldSerializeStatistics() => ShouldSerializeDefaultValues || (Statistics != DefaultStatistics);
|
||||
public bool ShouldSerializeSteamMessagePrefix() => ShouldSerializeDefaultValues || (SteamMessagePrefix != DefaultSteamMessagePrefix);
|
||||
public bool ShouldSerializeSteamOwnerID() => ShouldSerializeDefaultValues || (SteamOwnerID != DefaultSteamOwnerID);
|
||||
public bool ShouldSerializeSteamProtocols() => ShouldSerializeDefaultValues || (SteamProtocols != DefaultSteamProtocols);
|
||||
public bool ShouldSerializeUpdateChannel() => ShouldSerializeDefaultValues || (UpdateChannel != DefaultUpdateChannel);
|
||||
public bool ShouldSerializeUpdatePeriod() => ShouldSerializeDefaultValues || (UpdatePeriod != DefaultUpdatePeriod);
|
||||
public bool ShouldSerializeWebLimiterDelay() => ShouldSerializeDefaultValues || (WebLimiterDelay != DefaultWebLimiterDelay);
|
||||
public bool ShouldSerializeWebProxyPassword() => ShouldSerializeSensitiveDetails && (ShouldSerializeDefaultValues || (WebProxyPassword != DefaultWebProxyPassword));
|
||||
public bool ShouldSerializeWebProxyText() => ShouldSerializeDefaultValues || (WebProxyText != DefaultWebProxyText);
|
||||
public bool ShouldSerializeWebProxyUsername() => ShouldSerializeDefaultValues || (WebProxyUsername != DefaultWebProxyUsername);
|
||||
|
||||
// ReSharper restore UnusedMember.Global
|
||||
}
|
||||
|
||||
@@ -136,8 +136,8 @@ namespace ArchiSteamFarm {
|
||||
return globalDatabase;
|
||||
}
|
||||
|
||||
internal HashSet<uint> GetPackageIDs(uint appID, ICollection<uint> packageIDs) {
|
||||
if ((appID == 0) || (packageIDs == null) || (packageIDs.Count == 0)) {
|
||||
internal HashSet<uint> GetPackageIDs(uint appID, IEnumerable<uint> packageIDs) {
|
||||
if ((appID == 0) || (packageIDs == null)) {
|
||||
ASF.ArchiLogger.LogNullError(nameof(appID) + " || " + nameof(packageIDs));
|
||||
|
||||
return null;
|
||||
|
||||
@@ -66,8 +66,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
|
||||
return BadRequest(new GenericResponse(false, errorMessage));
|
||||
}
|
||||
|
||||
request.GlobalConfig.ShouldSerializeEverything = false;
|
||||
request.GlobalConfig.ShouldSerializeDefaultValues = false;
|
||||
request.GlobalConfig.ShouldSerializeHelperProperties = false;
|
||||
request.GlobalConfig.ShouldSerializeSensitiveDetails = true;
|
||||
|
||||
if (!request.GlobalConfig.IsWebProxyPasswordSet && ASF.GlobalConfig.IsWebProxyPasswordSet) {
|
||||
request.GlobalConfig.WebProxyPassword = ASF.GlobalConfig.WebProxyPassword;
|
||||
|
||||
@@ -100,8 +100,9 @@ namespace ArchiSteamFarm.IPC.Controllers.Api {
|
||||
return BadRequest(new GenericResponse(false, errorMessage));
|
||||
}
|
||||
|
||||
request.BotConfig.ShouldSerializeEverything = false;
|
||||
request.BotConfig.ShouldSerializeDefaultValues = false;
|
||||
request.BotConfig.ShouldSerializeHelperProperties = false;
|
||||
request.BotConfig.ShouldSerializeSensitiveDetails = true;
|
||||
|
||||
HashSet<string> bots = botNames.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Where(botName => botName != SharedInfo.ASF).ToHashSet(Bot.BotsComparer);
|
||||
|
||||
|
||||
39
ArchiSteamFarm/IPC/Controllers/Api/PluginsController.cs
Normal file
39
ArchiSteamFarm/IPC/Controllers/Api/PluginsController.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2020 Ł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.Collections.Generic;
|
||||
using System.Net;
|
||||
using ArchiSteamFarm.IPC.Responses;
|
||||
using ArchiSteamFarm.Plugins;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Controllers.Api {
|
||||
[Route("Api/Plugins")]
|
||||
public sealed class PluginsController : ArchiController {
|
||||
[HttpGet]
|
||||
[ProducesResponseType(typeof(GenericResponse<IReadOnlyCollection<IPlugin>>), (int) HttpStatusCode.OK)]
|
||||
public ActionResult<GenericResponse<IReadOnlyCollection<IPlugin>>> PluginsGet() {
|
||||
IReadOnlyCollection<IPlugin> activePlugins = PluginsCore.ActivePlugins ?? (IReadOnlyCollection<IPlugin>) new IPlugin[0];
|
||||
|
||||
return Ok(new GenericResponse<IReadOnlyCollection<IPlugin>>(activePlugins));
|
||||
}
|
||||
}
|
||||
}
|
||||
89
ArchiSteamFarm/IPC/Integration/EnumSchemaFilter.cs
Normal file
89
ArchiSteamFarm/IPC/Integration/EnumSchemaFilter.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
// _ _ _ ____ _ _____
|
||||
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
||||
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
||||
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
||||
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
||||
// |
|
||||
// Copyright 2015-2020 Ł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;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Extensions;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace ArchiSteamFarm.IPC.Integration {
|
||||
[UsedImplicitly]
|
||||
internal sealed class EnumSchemaFilter : ISchemaFilter {
|
||||
public void Apply([NotNull] OpenApiSchema schema, [NotNull] SchemaFilterContext context) {
|
||||
if ((schema == null) || (context == null)) {
|
||||
throw new ArgumentNullException(nameof(schema) + " || " + nameof(context));
|
||||
}
|
||||
|
||||
if (!context.Type.IsEnum) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Type.IsDefined(typeof(FlagsAttribute), false)) {
|
||||
schema.Format = "flags";
|
||||
}
|
||||
|
||||
OpenApiObject definition = new OpenApiObject();
|
||||
|
||||
foreach (object enumValue in context.Type.GetEnumValues()) {
|
||||
string enumName = Enum.GetName(context.Type, enumValue);
|
||||
|
||||
if (string.IsNullOrEmpty(enumName)) {
|
||||
enumName = enumValue.ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(enumName)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
IOpenApiAny enumObject;
|
||||
|
||||
if (TryCast(enumValue, out int intValue)) {
|
||||
enumObject = new OpenApiInteger(intValue);
|
||||
} else if (TryCast(enumValue, out long longValue)) {
|
||||
enumObject = new OpenApiLong(longValue);
|
||||
} else if (TryCast(enumValue, out ulong ulongValue)) {
|
||||
// OpenApi spec doesn't support ulongs as of now
|
||||
enumObject = new OpenApiString(ulongValue.ToString());
|
||||
} else {
|
||||
throw new ArgumentOutOfRangeException(nameof(enumValue));
|
||||
}
|
||||
|
||||
definition.Add(enumName, enumObject);
|
||||
}
|
||||
|
||||
schema.AddExtension("x-definition", definition);
|
||||
}
|
||||
|
||||
private static bool TryCast<T>(object value, out T typedValue) {
|
||||
try {
|
||||
typedValue = (T) Convert.ChangeType(value, typeof(T));
|
||||
|
||||
return true;
|
||||
} catch (InvalidCastException) {
|
||||
typedValue = default;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,6 +167,7 @@ namespace ArchiSteamFarm.IPC {
|
||||
);
|
||||
|
||||
options.EnableAnnotations(true);
|
||||
options.SchemaFilter<EnumSchemaFilter>();
|
||||
|
||||
options.SwaggerDoc(
|
||||
SharedInfo.ASF, new OpenApiInfo {
|
||||
@@ -234,9 +235,6 @@ namespace ArchiSteamFarm.IPC {
|
||||
// Fix default contract resolver to use original names and not a camel case
|
||||
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
|
||||
|
||||
// TODO: Enable this again once ASF-ui adds support in https://github.com/JustArchiNET/ASF-ui/issues/871
|
||||
//options.SerializerSettings.Converters.Add(new StringEnumConverter());
|
||||
|
||||
if (Debugging.IsUserDebugging) {
|
||||
options.SerializerSettings.Formatting = Formatting.Indented;
|
||||
}
|
||||
|
||||
@@ -283,7 +283,9 @@ namespace ArchiSteamFarm.Json {
|
||||
ProfileModifier,
|
||||
Sticker,
|
||||
ChatEffect,
|
||||
MiniProfileBackground
|
||||
MiniProfileBackground,
|
||||
AvatarProfileFrame,
|
||||
AnimatedAvatar
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,6 +605,10 @@ namespace ArchiSteamFarm.Json {
|
||||
return Asset.EType.ChatEffect;
|
||||
case "item_class_13":
|
||||
return Asset.EType.MiniProfileBackground;
|
||||
case "item_class_14":
|
||||
return Asset.EType.AvatarProfileFrame;
|
||||
case "item_class_15":
|
||||
return Asset.EType.AnimatedAvatar;
|
||||
default:
|
||||
ASF.ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(tag.Value), tag.Value));
|
||||
|
||||
@@ -702,6 +708,15 @@ namespace ArchiSteamFarm.Json {
|
||||
private NewDiscoveryQueueResponse() { }
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class ProfileEditData {
|
||||
[JsonProperty(PropertyName = "Privacy", Required = Required.Always)]
|
||||
internal readonly UserPrivacy Privacy;
|
||||
|
||||
[JsonConstructor]
|
||||
private ProfileEditData() { }
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
internal sealed class RedeemWalletResponse : EResultResponse {
|
||||
[JsonProperty(PropertyName = "wallet", Required = Required.DisallowNull)]
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm.Plugins {
|
||||
[PublicAPI]
|
||||
@@ -29,6 +30,7 @@ namespace ArchiSteamFarm.Plugins {
|
||||
/// ASF will use this property as general plugin identifier for the user.
|
||||
/// </summary>
|
||||
/// <returns>String that will be used as the name of this plugin.</returns>
|
||||
[JsonProperty]
|
||||
[NotNull]
|
||||
string Name { get; }
|
||||
|
||||
@@ -37,6 +39,7 @@ namespace ArchiSteamFarm.Plugins {
|
||||
/// You have a freedom in deciding what versioning you want to use, this is for identification purposes only.
|
||||
/// </summary>
|
||||
/// <returns>Version that will be shown to the user when plugin is loaded.</returns>
|
||||
[JsonProperty]
|
||||
[NotNull]
|
||||
Version Version { get; }
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ namespace ArchiSteamFarm.Plugins {
|
||||
internal static class PluginsCore {
|
||||
internal static bool HasCustomPluginsLoaded => HasActivePluginsLoaded && ActivePlugins.Any(plugin => !(plugin is OfficialPlugin officialPlugin) || !officialPlugin.HasSameVersion());
|
||||
|
||||
private static bool HasActivePluginsLoaded => ActivePlugins?.Count > 0;
|
||||
|
||||
[ImportMany]
|
||||
private static ImmutableHashSet<IPlugin> ActivePlugins { get; set; }
|
||||
internal static ImmutableHashSet<IPlugin> ActivePlugins { get; private set; }
|
||||
|
||||
private static bool HasActivePluginsLoaded => ActivePlugins?.Count > 0;
|
||||
|
||||
[ItemNotNull]
|
||||
internal static async Task<StringComparer> GetBotsComparer() {
|
||||
|
||||
@@ -214,7 +214,7 @@ namespace ArchiSteamFarm {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
globalConfig = GlobalConfig.Create();
|
||||
globalConfig = new GlobalConfig();
|
||||
}
|
||||
|
||||
ASF.InitGlobalConfig(globalConfig);
|
||||
|
||||
@@ -34,8 +34,8 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace ArchiSteamFarm {
|
||||
internal sealed class Statistics : IAsyncDisposable {
|
||||
private const ushort MaxItemsForFairBots = ArchiWebHandler.MaxItemsInSingleInventoryRequest * WebBrowser.MaxTries; // Determines which fair bots we'll deprioritize when matching due to excessive number of inventory requests they need to make, which are likely to fail in the process or cause excessive delays
|
||||
private const byte MaxMatchedBotsHard = 40; // Determines how many bots we can attempt to match in total, where match attempt is equal to analyzing bot's inventory
|
||||
private const byte MaxMatchedBotsSoft = MaxMatchedBotsHard / 2; // Determines how many consecutive empty matches we need to get before we decide to skip bots from the same category
|
||||
private const byte MaxMatchingRounds = 10; // Determines maximum amount of matching rounds we're going to consider before leaving the rest of work for the next batch
|
||||
private const byte MinAnnouncementCheckTTL = 6; // Minimum amount of hours we must wait before checking eligibility for Announcement, should be lower than MinPersonaStateTTL
|
||||
private const byte MinHeartBeatTTL = 10; // Minimum amount of minutes we must wait before sending next HeartBeat
|
||||
@@ -325,10 +325,11 @@ namespace ArchiSteamFarm {
|
||||
|
||||
Dictionary<ulong, (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs)> triedSteamIDs = new Dictionary<ulong, (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs)>();
|
||||
|
||||
bool match = true;
|
||||
bool shouldContinueMatching = true;
|
||||
bool tradedSomething = false;
|
||||
|
||||
for (byte i = 0; (i < MaxMatchingRounds) && match; i++) {
|
||||
if (i > 0) {
|
||||
for (byte i = 0; (i < MaxMatchingRounds) && shouldContinueMatching; i++) {
|
||||
if ((i > 0) && tradedSomething) {
|
||||
// After each round we wait at least 5 minutes for all bots to react
|
||||
await Task.Delay(5 * 60 * 1000).ConfigureAwait(false);
|
||||
}
|
||||
@@ -341,7 +342,7 @@ namespace ArchiSteamFarm {
|
||||
|
||||
using (await Bot.Actions.GetTradingLock().ConfigureAwait(false)) {
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ActivelyMatchingItems, i));
|
||||
match = await MatchActivelyRound(acceptedMatchableTypes, triedSteamIDs).ConfigureAwait(false);
|
||||
(shouldContinueMatching, tradedSomething) = await MatchActivelyRound(acceptedMatchableTypes, triedSteamIDs).ConfigureAwait(false);
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.DoneActivelyMatchingItems, i));
|
||||
}
|
||||
}
|
||||
@@ -352,11 +353,11 @@ namespace ArchiSteamFarm {
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> MatchActivelyRound(IReadOnlyCollection<Steam.Asset.EType> acceptedMatchableTypes, IDictionary<ulong, (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs)> triedSteamIDs) {
|
||||
private async Task<(bool ShouldContinueMatching, bool TradedSomething)> MatchActivelyRound(IReadOnlyCollection<Steam.Asset.EType> acceptedMatchableTypes, IDictionary<ulong, (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs)> triedSteamIDs) {
|
||||
if ((acceptedMatchableTypes == null) || (acceptedMatchableTypes.Count == 0) || (triedSteamIDs == null)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(acceptedMatchableTypes) + " || " + nameof(triedSteamIDs));
|
||||
|
||||
return false;
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
HashSet<Steam.Asset> ourInventory;
|
||||
@@ -364,17 +365,17 @@ namespace ArchiSteamFarm {
|
||||
try {
|
||||
ourInventory = await Bot.ArchiWebHandler.GetInventoryAsync().Where(item => acceptedMatchableTypes.Contains(item.Type)).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException) {
|
||||
return false;
|
||||
return (false, false);
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
return false;
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
if (ourInventory.Count == 0) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(ourInventory)));
|
||||
|
||||
return false;
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
(Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> ourFullState, Dictionary<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity), Dictionary<ulong, uint>> ourTradableState) = Trading.GetDividedInventoryState(ourInventory);
|
||||
@@ -383,7 +384,7 @@ namespace ArchiSteamFarm {
|
||||
// User doesn't have any more dupes in the inventory
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(ourFullState) + " || " + nameof(ourTradableState)));
|
||||
|
||||
return false;
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
ImmutableHashSet<ListedUser> listedUsers = await GetListedUsers().ConfigureAwait(false);
|
||||
@@ -391,20 +392,14 @@ namespace ArchiSteamFarm {
|
||||
if ((listedUsers == null) || (listedUsers.Count == 0)) {
|
||||
Bot.ArchiLogger.LogGenericTrace(string.Format(Strings.ErrorIsEmpty, nameof(listedUsers)));
|
||||
|
||||
return false;
|
||||
return (false, false);
|
||||
}
|
||||
|
||||
bool skipAnyBots = false;
|
||||
byte emptyMatches = 0;
|
||||
byte totalMatches = 0;
|
||||
|
||||
HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> skippedSetsThisRound = new HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)>();
|
||||
|
||||
foreach (ListedUser listedUser in listedUsers.Where(listedUser => (listedUser.SteamID != Bot.SteamID) && acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && (!triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) || (attempt.Tries < byte.MaxValue)) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderBy(listedUser => triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) ? attempt.Tries : 0).ThenByDescending(listedUser => listedUser.MatchEverything).ThenByDescending(listedUser => listedUser.Score)) {
|
||||
if (listedUser.MatchEverything && skipAnyBots) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (ListedUser listedUser in listedUsers.Where(listedUser => (listedUser.SteamID != Bot.SteamID) && acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && (!triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) || (attempt.Tries < byte.MaxValue)) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderBy(listedUser => triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) ? attempt.Tries : 0).ThenByDescending(listedUser => listedUser.MatchEverything).ThenByDescending(listedUser => listedUser.MatchEverything || (listedUser.ItemsCount < MaxItemsForFairBots)).ThenByDescending(listedUser => listedUser.Score)) {
|
||||
HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> wantedSets = ourTradableState.Keys.Where(set => !skippedSetsThisRound.Contains(set) && listedUser.MatchableTypes.Contains(set.Type)).ToHashSet();
|
||||
|
||||
if (wantedSets.Count == 0) {
|
||||
@@ -468,7 +463,7 @@ namespace ArchiSteamFarm {
|
||||
if (!ourFullSet.TryGetValue(classID, out uint fullAmount) || (fullAmount == 0) || (fullAmount < amount)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(fullAmount));
|
||||
|
||||
return false;
|
||||
return (false, skippedSetsThisRound.Count > 0);
|
||||
}
|
||||
|
||||
if (fullAmount > amount) {
|
||||
@@ -480,7 +475,7 @@ namespace ArchiSteamFarm {
|
||||
if (!ourTradableSet.TryGetValue(classID, out uint tradableAmount) || (tradableAmount == 0) || (tradableAmount < amount)) {
|
||||
Bot.ArchiLogger.LogNullError(nameof(tradableAmount));
|
||||
|
||||
return false;
|
||||
return (false, skippedSetsThisRound.Count > 0);
|
||||
}
|
||||
|
||||
if (fullAmount > amount) {
|
||||
@@ -606,7 +601,7 @@ namespace ArchiSteamFarm {
|
||||
// Failsafe
|
||||
Bot.ArchiLogger.LogGenericError(string.Format(Strings.WarningFailedWithError, Strings.ErrorAborted));
|
||||
|
||||
return false;
|
||||
return (false, skippedSetsThisRound.Count > 0);
|
||||
}
|
||||
|
||||
if (triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) previousAttempt)) {
|
||||
@@ -626,8 +621,6 @@ namespace ArchiSteamFarm {
|
||||
|
||||
triedSteamIDs[listedUser.SteamID] = (++previousAttempt.Tries, previousAttempt.GivenAssetIDs, previousAttempt.ReceivedAssetIDs);
|
||||
|
||||
emptyMatches = 0;
|
||||
|
||||
Bot.ArchiLogger.LogGenericTrace(Bot.SteamID + " <- " + string.Join(", ", itemsToReceive.Select(item => item.RealAppID + "/" + item.Type + "-" + item.ClassID + " #" + item.Amount)) + " | " + string.Join(", ", itemsToGive.Select(item => item.RealAppID + "/" + item.Type + "-" + item.ClassID + " #" + item.Amount)) + " -> " + listedUser.SteamID);
|
||||
|
||||
(bool success, HashSet<ulong> mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, true).ConfigureAwait(false);
|
||||
@@ -638,7 +631,7 @@ namespace ArchiSteamFarm {
|
||||
if (!twoFactorSuccess) {
|
||||
Bot.ArchiLogger.LogGenericTrace(Strings.WarningFailed);
|
||||
|
||||
return false;
|
||||
return (false, skippedSetsThisRound.Count > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,15 +654,6 @@ namespace ArchiSteamFarm {
|
||||
triedSteamIDs[listedUser.SteamID] = (byte.MaxValue, null, null);
|
||||
}
|
||||
|
||||
if (++emptyMatches >= MaxMatchedBotsSoft) {
|
||||
if (skipAnyBots) {
|
||||
break;
|
||||
}
|
||||
|
||||
skipAnyBots = true;
|
||||
emptyMatches = 0;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -691,11 +675,17 @@ namespace ArchiSteamFarm {
|
||||
|
||||
Bot.ArchiLogger.LogGenericInfo(string.Format(Strings.ActivelyMatchingItemsRound, skippedSetsThisRound.Count));
|
||||
|
||||
return skippedSetsThisRound.Count > 0;
|
||||
// Keep matching when we either traded something this round (so it makes sense for a refresh) or if we didn't try all available bots yet (so it makes sense to keep going)
|
||||
return ((totalMatches > 0) && ((skippedSetsThisRound.Count > 0) || triedSteamIDs.Values.All(data => data.Tries < 2)), skippedSetsThisRound.Count > 0);
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
||||
private sealed class ListedUser {
|
||||
#pragma warning disable 649
|
||||
[JsonProperty(PropertyName = "items_count", Required = Required.Always)]
|
||||
internal readonly ushort ItemsCount;
|
||||
#pragma warning restore 649
|
||||
|
||||
internal readonly HashSet<Steam.Asset.EType> MatchableTypes = new HashSet<Steam.Asset.EType>();
|
||||
|
||||
#pragma warning disable 649
|
||||
@@ -715,11 +705,6 @@ namespace ArchiSteamFarm {
|
||||
private readonly ushort GamesCount;
|
||||
#pragma warning restore 649
|
||||
|
||||
#pragma warning disable 649
|
||||
[JsonProperty(PropertyName = "items_count", Required = Required.Always)]
|
||||
private readonly ushort ItemsCount;
|
||||
#pragma warning restore 649
|
||||
|
||||
internal bool MatchEverything { get; private set; }
|
||||
|
||||
#pragma warning disable IDE0051
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>4.2.2.8</Version>
|
||||
<Version>4.2.3.4</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
ARG DOTNET_ARCH=
|
||||
|
||||
FROM node:lts AS build-node
|
||||
WORKDIR /app
|
||||
COPY ASF-ui .
|
||||
@@ -31,7 +33,6 @@ RUN dotnet --info && \
|
||||
if [ -d "ArchiSteamFarm/overlay/generic" ]; then cp "ArchiSteamFarm/overlay/generic/"* "out/result"; fi && \
|
||||
if [ -f "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/${STEAM_TOKEN_DUMPER_NAME}.dll" ]; then mkdir -p "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; cp "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/${STEAM_TOKEN_DUMPER_NAME}.dll" "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; fi
|
||||
|
||||
ARG DOTNET_ARCH=
|
||||
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim${DOTNET_ARCH} AS runtime
|
||||
ENV ASPNETCORE_URLS=
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT 1
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
ARG DOTNET_ARCH=
|
||||
|
||||
FROM node:lts AS build-node
|
||||
WORKDIR /app
|
||||
COPY ASF-ui .
|
||||
@@ -31,7 +33,6 @@ RUN dotnet --info && \
|
||||
if [ -d "ArchiSteamFarm/overlay/linux-${ASF_ARCH}" ]; then cp "ArchiSteamFarm/overlay/linux-${ASF_ARCH}/"* "out/result"; fi && \
|
||||
if [ -f "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/${STEAM_TOKEN_DUMPER_NAME}.dll" ]; then mkdir -p "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; cp "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/${STEAM_TOKEN_DUMPER_NAME}.dll" "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; fi
|
||||
|
||||
ARG DOTNET_ARCH=
|
||||
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1-buster-slim${DOTNET_ARCH} AS runtime
|
||||
ENV ASPNETCORE_URLS=
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT 1
|
||||
|
||||
0
hooks/build
Normal file → Executable file
0
hooks/build
Normal file → Executable file
2
wiki
2
wiki
Submodule wiki updated: d4db33893f...6bc6f038c7
Reference in New Issue
Block a user