diff --git a/.github/crowdin.yml b/.github/crowdin.yml
index 0bab922bc..003e535e4 100644
--- a/.github/crowdin.yml
+++ b/.github/crowdin.yml
@@ -12,6 +12,17 @@
".zh-TW.resx": ".zh-Hant.resx"
}
},
+ {
+ "source": "/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/Strings.resx",
+ "translation": "/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/Strings.%locale%.resx",
+ "translation_replace": {
+ ".lol-US.resx": ".qps-Ploc.resx",
+ ".sr-CS.resx": ".sr-Latn.resx",
+ ".zh-CN.resx": ".zh-Hans.resx",
+ ".zh-HK.resx": ".zh-Hant-HK.resx",
+ ".zh-TW.resx": ".zh-Hant.resx"
+ }
+ },
{
"source": "/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.resx",
"translation": "/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.%locale%.resx",
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 4c6acac79..1b25cb35a 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -11,7 +11,7 @@ env:
NET_CORE_VERSION: net7.0
NET_FRAMEWORK_VERSION: net481
NODE_JS_VERSION: 'lts/*'
- STEAM_TOKEN_DUMPER_NAME: ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
+ PLUGINS: ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
STEAM_TOKEN_DUMPER_TOKEN: ${{ secrets.STEAM_TOKEN_DUMPER_TOKEN }}
jobs:
@@ -83,15 +83,35 @@ jobs:
}
}
+ - name: Prepare for publishing on Unix
+ if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
+ shell: bash
+ run: |
+ set -euo pipefail
+
+ dotnet restore
+ dotnet build ArchiSteamFarm -c "$CONFIGURATION" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
+
+ - name: Prepare for publishing on Windows
+ if: startsWith(matrix.os, 'windows-')
+ shell: pwsh
+ run: |
+ Set-StrictMode -Version Latest
+ $ErrorActionPreference = 'Stop'
+ $ProgressPreference = 'SilentlyContinue'
+
+ dotnet restore
+ dotnet build ArchiSteamFarm -c "$env:CONFIGURATION" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
+
- name: Prepare ArchiSteamFarm.OfficialPlugins.SteamTokenDumper on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
shell: sh
run: |
set -eu
- if [ -n "${STEAM_TOKEN_DUMPER_TOKEN-}" ] && [ -f "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs" ]; then
- sed "s/STEAM_TOKEN_DUMPER_TOKEN/${STEAM_TOKEN_DUMPER_TOKEN}/g" "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs" > "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs.new"
- mv "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs.new" "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs"
+ if [ -n "${STEAM_TOKEN_DUMPER_TOKEN-}" ] && [ -f "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs" ]; then
+ sed "s/STEAM_TOKEN_DUMPER_TOKEN/${STEAM_TOKEN_DUMPER_TOKEN}/g" "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs" > "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs.new"
+ mv "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs.new" "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SharedInfo.cs"
fi
- name: Prepare ArchiSteamFarm.OfficialPlugins.SteamTokenDumper on Windows
@@ -102,19 +122,74 @@ jobs:
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
- if ((Test-Path env:STEAM_TOKEN_DUMPER_TOKEN) -and ($env:STEAM_TOKEN_DUMPER_TOKEN) -and (Test-Path "$env:STEAM_TOKEN_DUMPER_NAME\SharedInfo.cs" -PathType Leaf)) {
- (Get-Content "$env:STEAM_TOKEN_DUMPER_NAME\SharedInfo.cs").Replace('STEAM_TOKEN_DUMPER_TOKEN', "$env:STEAM_TOKEN_DUMPER_TOKEN") | Set-Content "$env:STEAM_TOKEN_DUMPER_NAME\SharedInfo.cs"
+ if ((Test-Path env:STEAM_TOKEN_DUMPER_TOKEN) -and ($env:STEAM_TOKEN_DUMPER_TOKEN) -and (Test-Path "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper\SharedInfo.cs" -PathType Leaf)) {
+ (Get-Content "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper\SharedInfo.cs").Replace('STEAM_TOKEN_DUMPER_TOKEN', "$env:STEAM_TOKEN_DUMPER_TOKEN") | Set-Content "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper\SharedInfo.cs"
}
- - name: Publish ArchiSteamFarm.OfficialPlugins.SteamTokenDumper for .NET Core
- run: dotnet publish "${{ env.STEAM_TOKEN_DUMPER_NAME }}" -c "${{ env.CONFIGURATION }}" -f "${{ env.NET_CORE_VERSION }}" -o "out/${{ env.STEAM_TOKEN_DUMPER_NAME }}/${{ env.NET_CORE_VERSION }}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --nologo
+ - name: Publish official plugins on Unix
+ if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
+ env:
+ MAX_JOBS: 3
+ shell: bash
+ run: |
+ set -euo pipefail
- - name: Publish ArchiSteamFarm.OfficialPlugins.SteamTokenDumper for .NET Framework
+ publish() {
+ dotnet publish "$1" -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/${1}/${NET_CORE_VERSION}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
+ }
+
+ for plugin in $PLUGINS; do
+ publish "$plugin" &
+
+ while [ "$(jobs -p | wc -l)" -ge "$MAX_JOBS" ]; do
+ sleep 1
+ done
+ done
+
+ wait
+
+ - name: Publish official plugins on Windows
if: startsWith(matrix.os, 'windows-')
- run: dotnet publish "${{ env.STEAM_TOKEN_DUMPER_NAME }}" -c "${{ env.CONFIGURATION }}" -f "${{ env.NET_FRAMEWORK_VERSION }}" -o "out/${{ env.STEAM_TOKEN_DUMPER_NAME }}/${{ env.NET_FRAMEWORK_VERSION }}" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --nologo
+ env:
+ MAX_JOBS: 2
+ shell: pwsh
+ run: |
+ Set-StrictMode -Version Latest
+ $ErrorActionPreference = 'Stop'
+ $ProgressPreference = 'SilentlyContinue'
- - name: Restore packages in preparation for ArchiSteamFarm publishing
- run: dotnet restore ArchiSteamFarm -p:ContinuousIntegrationBuild=true --nologo
+ $PublishBlock = {
+ param($plugin, $framework)
+
+ Set-StrictMode -Version Latest
+ $ErrorActionPreference = 'Stop'
+ $ProgressPreference = 'SilentlyContinue'
+
+ Set-Location "$env:GITHUB_WORKSPACE"
+
+ dotnet publish "$plugin" -c "$env:CONFIGURATION" -f "$framework" -o "out\$plugin\$framework" -p:ContinuousIntegrationBuild=true -p:TargetLatestRuntimePatch=false -p:UseAppHost=false --no-restore --nologo
+
+ if ($LastExitCode -ne 0) {
+ throw "Last command failed."
+ }
+ }
+
+ foreach ($plugin in $env:PLUGINS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
+ foreach ($framework in "$env:NET_CORE_VERSION","$env:NET_FRAMEWORK_VERSION") {
+ Start-Job -Name "$plugin $framework" $PublishBlock -ArgumentList "$plugin","$framework"
+
+ # Limit active jobs in parallel to help with memory usage
+ $jobs = $(Get-Job -State Running)
+
+ while (@($jobs).Count -ge $env:MAX_JOBS) {
+ Wait-Job -Job $jobs -Any | Out-Null
+
+ $jobs = $(Get-Job -State Running)
+ }
+ }
+ }
+
+ Get-Job | Receive-Job -Wait
- name: Publish ArchiSteamFarm on Unix
if: startsWith(matrix.os, 'macos-') || startsWith(matrix.os, 'ubuntu-')
@@ -134,11 +209,13 @@ jobs:
dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/${1}" "-p:ASFVariant=$1" -p:ContinuousIntegrationBuild=true --no-restore --nologo $variantArgs
- # If we're including SteamTokenDumper plugin for this framework, copy it to output directory
- if [ -d "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}" ]; then
- mkdir -p "out/${1}/plugins/${STEAM_TOKEN_DUMPER_NAME}"
- cp -pR "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/"* "out/${1}/plugins/${STEAM_TOKEN_DUMPER_NAME}"
- fi
+ # If we're including official plugins for this framework, copy them to output directory
+ for plugin in $PLUGINS; do
+ if [ -d "out/${plugin}/${NET_CORE_VERSION}" ]; then
+ mkdir -p "out/${1}/plugins/${plugin}"
+ cp -pR "out/${plugin}/${NET_CORE_VERSION}/"* "out/${1}/plugins/${plugin}"
+ fi
+ done
# Include .ico file for all platforms, since only Windows script can bundle it inside the exe
cp "resources/ASF.ico" "out/${1}/ArchiSteamFarm.ico"
@@ -244,13 +321,15 @@ jobs:
throw "Last command failed."
}
- # If we're including SteamTokenDumper plugin for this framework, copy it to output directory
- if (Test-Path "out\$env:STEAM_TOKEN_DUMPER_NAME\$targetFramework" -PathType Container) {
- if (!(Test-Path "out\$variant\plugins\$env:STEAM_TOKEN_DUMPER_NAME" -PathType Container)) {
- New-Item -ItemType Directory -Path "out\$variant\plugins\$env:STEAM_TOKEN_DUMPER_NAME" > $null
- }
+ # If we're including official plugins for this framework, copy them to output directory
+ foreach ($plugin in $env:PLUGINS.Split([char[]] $null, [System.StringSplitOptions]::RemoveEmptyEntries)) {
+ if (Test-Path "out\$plugin\$targetFramework" -PathType Container) {
+ if (!(Test-Path "out\$variant\plugins\$plugin" -PathType Container)) {
+ New-Item -ItemType Directory -Path "out\$variant\plugins\$plugin" > $null
+ }
- Copy-Item "out\$env:STEAM_TOKEN_DUMPER_NAME\$targetFramework\*" "out\$variant\plugins\$env:STEAM_TOKEN_DUMPER_NAME" -Recurse
+ Copy-Item "out\$plugin\$targetFramework\*" "out\$variant\plugins\$plugin" -Recurse
+ }
}
# Icon is available only in .NET Framework and .NET Core Windows build, we'll bundle the .ico file for other flavours
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/ArchiSteamFarm.OfficialPlugins.ItemsMatcher.csproj b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/ArchiSteamFarm.OfficialPlugins.ItemsMatcher.csproj
new file mode 100644
index 000000000..a4c076c5b
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/ArchiSteamFarm.OfficialPlugins.ItemsMatcher.csproj
@@ -0,0 +1,41 @@
+
+
+ Library
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ Strings.Designer.cs
+
+
+
+
+
+ True
+ Strings.resx
+ True
+
+
+
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/AssemblyInfo.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/AssemblyInfo.cs
new file mode 100644
index 000000000..e29ebf2a0
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/AssemblyInfo.cs
@@ -0,0 +1,24 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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;
+
+[assembly: CLSCompliant(false)]
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Backend.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Backend.cs
new file mode 100644
index 000000000..71b2dfd84
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Backend.cs
@@ -0,0 +1,120 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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 System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Net;
+using System.Threading.Tasks;
+using ArchiSteamFarm.Core;
+using ArchiSteamFarm.IPC.Responses;
+using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Requests;
+using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Responses;
+using ArchiSteamFarm.Steam;
+using ArchiSteamFarm.Steam.Data;
+using ArchiSteamFarm.Steam.Storage;
+using ArchiSteamFarm.Storage;
+using ArchiSteamFarm.Web;
+using ArchiSteamFarm.Web.Responses;
+
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
+
+internal static class Backend {
+ internal static async Task AnnounceForListing(Bot bot, IReadOnlyList inventory, IReadOnlyCollection acceptedMatchableTypes, string tradeToken, string? nickname = null, string? avatarHash = null) {
+ ArgumentNullException.ThrowIfNull(bot);
+
+ if ((inventory == null) || (inventory.Count == 0)) {
+ throw new ArgumentNullException(nameof(inventory));
+ }
+
+ if ((acceptedMatchableTypes == null) || (acceptedMatchableTypes.Count == 0)) {
+ throw new ArgumentNullException(nameof(acceptedMatchableTypes));
+ }
+
+ if (string.IsNullOrEmpty(tradeToken)) {
+ throw new ArgumentNullException(nameof(tradeToken));
+ }
+
+ if (tradeToken.Length != BotConfig.SteamTradeTokenLength) {
+ throw new ArgumentOutOfRangeException(nameof(tradeToken));
+ }
+
+ Uri request = new(ArchiNet.URL, "/Api/Listing/Announce");
+
+ AnnouncementRequest data = new(ASF.GlobalDatabase?.Identifier ?? Guid.NewGuid(), bot.SteamID, tradeToken, inventory, acceptedMatchableTypes, bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything), ASF.GlobalConfig?.MaxTradeHoldDuration ?? GlobalConfig.DefaultMaxTradeHoldDuration, nickname, avatarHash);
+
+ BasicResponse? response = await bot.ArchiWebHandler.WebBrowser.UrlPost(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors).ConfigureAwait(false);
+
+ return response?.StatusCode;
+ }
+
+ internal static async Task<(HttpStatusCode StatusCode, ImmutableHashSet Users)?> GetListedUsersForMatching(Guid licenseID, Bot bot, IReadOnlyCollection inventory, IReadOnlyCollection acceptedMatchableTypes, string tradeToken) {
+ if (licenseID == Guid.Empty) {
+ throw new ArgumentOutOfRangeException(nameof(licenseID));
+ }
+
+ ArgumentNullException.ThrowIfNull(bot);
+
+ if ((inventory == null) || (inventory.Count == 0)) {
+ throw new ArgumentNullException(nameof(inventory));
+ }
+
+ if ((acceptedMatchableTypes == null) || (acceptedMatchableTypes.Count == 0)) {
+ throw new ArgumentNullException(nameof(acceptedMatchableTypes));
+ }
+
+ if (string.IsNullOrEmpty(tradeToken)) {
+ throw new ArgumentNullException(nameof(tradeToken));
+ }
+
+ if (tradeToken.Length != BotConfig.SteamTradeTokenLength) {
+ throw new ArgumentOutOfRangeException(nameof(tradeToken));
+ }
+
+ Uri request = new(ArchiNet.URL, "/Api/Listing/Inventories");
+
+ Dictionary headers = new(1, StringComparer.Ordinal) {
+ { "X-License-Key", licenseID.ToString("N") }
+ };
+
+ InventoriesRequest data = new(ASF.GlobalDatabase?.Identifier ?? Guid.NewGuid(), bot.SteamID, tradeToken, inventory, acceptedMatchableTypes, ASF.GlobalConfig?.MaxTradeHoldDuration ?? GlobalConfig.DefaultMaxTradeHoldDuration);
+
+ ObjectResponse>>? response = await bot.ArchiWebHandler.WebBrowser.UrlPostToJsonObject>, InventoriesRequest>(request, headers, data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.AllowInvalidBodyOnErrors).ConfigureAwait(false);
+
+ if (response == null) {
+ return null;
+ }
+
+ return (response.StatusCode, response.Content?.Result ?? ImmutableHashSet.Empty);
+ }
+
+ internal static async Task HeartBeatForListing(Bot bot) {
+ ArgumentNullException.ThrowIfNull(bot);
+
+ Uri request = new(ArchiNet.URL, "/Api/Listing/HeartBeat");
+
+ HeartBeatRequest data = new(ASF.GlobalDatabase?.Identifier ?? Guid.NewGuid(), bot.SteamID);
+
+ BasicResponse? response = await bot.ArchiWebHandler.WebBrowser.UrlPost(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors).ConfigureAwait(false);
+
+ return response?.StatusCode;
+ }
+}
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/ItemsMatcherPlugin.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/ItemsMatcherPlugin.cs
new file mode 100644
index 000000000..2e57e6792
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/ItemsMatcherPlugin.cs
@@ -0,0 +1,88 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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 System.Collections.Concurrent;
+using System.Composition;
+using System.Threading.Tasks;
+using ArchiSteamFarm.Core;
+using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization;
+using ArchiSteamFarm.Plugins;
+using ArchiSteamFarm.Plugins.Interfaces;
+using ArchiSteamFarm.Steam;
+using ArchiSteamFarm.Steam.Storage;
+using Newtonsoft.Json;
+using SteamKit2;
+
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
+
+[Export(typeof(IPlugin))]
+internal sealed class ItemsMatcherPlugin : OfficialPlugin, IBot, IBotIdentity {
+ private static readonly ConcurrentDictionary RemoteCommunications = new();
+
+ [JsonProperty]
+ public override string Name => nameof(ItemsMatcherPlugin);
+
+ [JsonProperty]
+ public override Version Version => typeof(ItemsMatcherPlugin).Assembly.GetName().Version ?? throw new InvalidOperationException(nameof(Version));
+
+ public async Task OnBotDestroy(Bot bot) {
+ ArgumentNullException.ThrowIfNull(bot);
+
+ if (RemoteCommunications.TryRemove(bot, out RemoteCommunication? remoteCommunications)) {
+ await remoteCommunications.DisposeAsync().ConfigureAwait(false);
+ }
+ }
+
+ public async Task OnBotInit(Bot bot) {
+ ArgumentNullException.ThrowIfNull(bot);
+
+ if (RemoteCommunications.TryRemove(bot, out RemoteCommunication? remoteCommunications)) {
+ await remoteCommunications.DisposeAsync().ConfigureAwait(false);
+ }
+
+ if (bot.BotConfig.RemoteCommunication == BotConfig.ERemoteCommunication.None) {
+ return;
+ }
+
+ RemoteCommunication remoteCommunication = new(bot);
+
+ if (!RemoteCommunications.TryAdd(bot, remoteCommunication)) {
+ await remoteCommunication.DisposeAsync().ConfigureAwait(false);
+ }
+ }
+
+ public override Task OnLoaded() {
+ Utilities.WarnAboutIncompleteTranslation(Strings.ResourceManager);
+
+ return Task.CompletedTask;
+ }
+
+ public async Task OnSelfPersonaState(Bot bot, SteamFriends.PersonaStateCallback data, string? nickname, string? avatarHash) {
+ ArgumentNullException.ThrowIfNull(bot);
+
+ if (!RemoteCommunications.TryGetValue(bot, out RemoteCommunication? remoteCommunication)) {
+ return;
+ }
+
+ await remoteCommunication.OnPersonaState(nickname, avatarHash).ConfigureAwait(false);
+ }
+}
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/README.md b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/README.md
new file mode 100644
index 000000000..4d3bb618e
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/README.md
@@ -0,0 +1,3 @@
+This directory contains ASF strings for display and localization purposes.
+
+All strings used by ASF can be found in main `Strings.resx` file, and that's also the only `resx` file that should be modified - all other `resx` files are managed automatically and should not be touched. Please visit **[localization](https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Localization)** section on the wiki if you want to improve translation of other files.
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/Strings.Designer.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/Strings.Designer.cs
new file mode 100644
index 000000000..63042578e
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/Strings.Designer.cs
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization {
+ using System;
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Strings {
+
+ private static System.Resources.ResourceManager resourceMan;
+
+ private static System.Globalization.CultureInfo resourceCulture;
+
+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Strings() {
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.Equals(null, resourceMan)) {
+ System.Resources.ResourceManager temp = new System.Resources.ResourceManager("ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization.Strings", typeof(Strings).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ internal static string ActivelyMatchingItemsRound {
+ get {
+ return ResourceManager.GetString("ActivelyMatchingItemsRound", resourceCulture);
+ }
+ }
+
+ internal static string ListingAnnouncing {
+ get {
+ return ResourceManager.GetString("ListingAnnouncing", resourceCulture);
+ }
+ }
+
+ internal static string MatchingFound {
+ get {
+ return ResourceManager.GetString("MatchingFound", resourceCulture);
+ }
+ }
+
+ internal static string TradeOfferFailed {
+ get {
+ return ResourceManager.GetString("TradeOfferFailed", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/Strings.resx b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/Strings.resx
new file mode 100644
index 000000000..0949149bf
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Localization/Strings.resx
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
+ PublicKeyToken=b77a5c561934e089
+
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral,
+ PublicKeyToken=b77a5c561934e089
+
+
+
+ Matched a total of {0} sets this round.
+ {0} will be replaced by number of sets traded
+
+
+ Announcing {0} ({1}) with inventory made out of {2} items in total on the listing...
+ {0} will be replaced by steam ID (number), {1} will be replaced by user's nickname, {2} will be replaced with number of items in the inventory
+
+
+ Matched a total of {0} items with bot {1} ({2}), sending trade offer...
+ {0} will be replaced by number of items matched, {1} will be replaced by steam ID (number), {2} will be replaced by user's nickname
+
+
+ Failed to send a trade offer to bot {0} ({1}), moving on...
+ {0} will be replaced by steam ID (number), {1} will be replaced by user's nickname'
+
+
diff --git a/ArchiSteamFarm/Core/RemoteCommunication.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs
similarity index 65%
rename from ArchiSteamFarm/Core/RemoteCommunication.cs
rename to ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs
index 788dc84ef..8eb4975e4 100644
--- a/ArchiSteamFarm/Core/RemoteCommunication.cs
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs
@@ -28,27 +28,24 @@ using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
-using ArchiSteamFarm.Localization;
+using ArchiSteamFarm.Core;
+using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Localization;
+using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Responses;
using ArchiSteamFarm.Steam;
using ArchiSteamFarm.Steam.Cards;
using ArchiSteamFarm.Steam.Data;
using ArchiSteamFarm.Steam.Exchange;
-using ArchiSteamFarm.Steam.Integration;
using ArchiSteamFarm.Steam.Security;
using ArchiSteamFarm.Steam.Storage;
using ArchiSteamFarm.Storage;
-using ArchiSteamFarm.Web;
-namespace ArchiSteamFarm.Core;
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher;
internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
- 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 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 MinAnnouncementCheckTTL = 45; // Minimum amount of minutes 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
private const byte MinItemsCount = 100; // Minimum amount of items to be eligible for public listing
- private const byte MinPersonaStateTTL = 8; // Minimum amount of hours we must wait before requesting persona state update
+ private const byte MinPersonaStateTTL = 60; // Minimum amount of minutes we must wait before requesting persona state update
private static readonly ImmutableHashSet AcceptedMatchableTypes = ImmutableHashSet.Create(
Asset.EType.Emoticon,
@@ -59,6 +56,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
private readonly Bot Bot;
private readonly SemaphoreSlim MatchActivelySemaphore = new(1, 1);
+ private readonly Timer? HeartBeatTimer;
private readonly Timer? MatchActivelyTimer;
private readonly SemaphoreSlim RequestsSemaphore = new(1, 1);
@@ -68,15 +66,30 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
private bool ShouldSendHeartBeats;
internal RemoteCommunication(Bot bot) {
- Bot = bot ?? throw new ArgumentNullException(nameof(bot));
+ ArgumentNullException.ThrowIfNull(bot);
+
+ Bot = bot;
+
+ if (Bot.BotConfig.RemoteCommunication.HasFlag(BotConfig.ERemoteCommunication.PublicListing)) {
+ HeartBeatTimer = new Timer(
+ HeartBeat,
+ null,
+ TimeSpan.FromMinutes(MinHeartBeatTTL) + TimeSpan.FromSeconds(ASF.LoadBalancingDelay * Bot.Bots?.Count ?? 0),
+ TimeSpan.FromMinutes(1)
+ );
+ }
if (Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchActively)) {
- MatchActivelyTimer = new Timer(
- MatchActively,
- null,
- TimeSpan.FromHours(1) + TimeSpan.FromSeconds(ASF.LoadBalancingDelay * Bot.Bots?.Count ?? 0), // Delay
- TimeSpan.FromHours(8) // Period
- );
+ if ((ASF.GlobalConfig?.LicenseID != null) && (ASF.GlobalConfig.LicenseID != Guid.Empty)) {
+ MatchActivelyTimer = new Timer(
+ MatchActively,
+ null,
+ TimeSpan.FromHours(1) + TimeSpan.FromSeconds(ASF.LoadBalancingDelay * Bot.Bots?.Count ?? 0),
+ TimeSpan.FromHours(6)
+ );
+ } else {
+ bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningNoLicense, nameof(BotConfig.ETradingPreferences.MatchActively)));
+ }
}
}
@@ -86,6 +99,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
RequestsSemaphore.Dispose();
// Those are objects that might be null and the check should be in-place
+ HeartBeatTimer?.Dispose();
MatchActivelyTimer?.Dispose();
}
@@ -95,18 +109,22 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
RequestsSemaphore.Dispose();
// Those are objects that might be null and the check should be in-place
+ if (HeartBeatTimer != null) {
+ await HeartBeatTimer.DisposeAsync().ConfigureAwait(false);
+ }
+
if (MatchActivelyTimer != null) {
await MatchActivelyTimer.DisposeAsync().ConfigureAwait(false);
}
}
- internal async Task OnHeartBeat() {
- if (!Bot.BotConfig.RemoteCommunication.HasFlag(BotConfig.ERemoteCommunication.PublicListing)) {
+ private async void HeartBeat(object? state = null) {
+ if (!Bot.IsConnectedAndLoggedOn || (Bot.HeartBeatFailures > 0)) {
return;
}
// Request persona update if needed
- if ((DateTime.UtcNow > LastPersonaStateRequest.AddHours(MinPersonaStateTTL)) && (DateTime.UtcNow > LastAnnouncementCheck.AddHours(MinAnnouncementCheckTTL))) {
+ if ((DateTime.UtcNow > LastPersonaStateRequest.AddMinutes(MinPersonaStateTTL)) && (DateTime.UtcNow > LastAnnouncementCheck.AddMinutes(MinAnnouncementCheckTTL))) {
LastPersonaStateRequest = DateTime.UtcNow;
Bot.RequestPersonaStateUpdate();
}
@@ -120,7 +138,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
try {
- HttpStatusCode? response = await ArchiNet.HeartBeatForListing(Bot).ConfigureAwait(false);
+ HttpStatusCode? response = await Backend.HeartBeatForListing(Bot).ConfigureAwait(false);
if (!response.HasValue) {
return;
@@ -139,29 +157,19 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
}
- internal async Task OnLoggedOn() {
- if (!Bot.BotConfig.RemoteCommunication.HasFlag(BotConfig.ERemoteCommunication.SteamGroup)) {
- return;
- }
-
- if (!await Bot.ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID).ConfigureAwait(false)) {
- Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(ArchiWebHandler.JoinGroup)));
- }
- }
-
internal async Task OnPersonaState(string? nickname = null, string? avatarHash = null) {
if (!Bot.BotConfig.RemoteCommunication.HasFlag(BotConfig.ERemoteCommunication.PublicListing)) {
return;
}
- if ((DateTime.UtcNow < LastAnnouncementCheck.AddHours(MinAnnouncementCheckTTL)) && (ShouldSendHeartBeats || (LastHeartBeat == DateTime.MinValue))) {
+ if ((DateTime.UtcNow < LastAnnouncementCheck.AddMinutes(MinAnnouncementCheckTTL)) && (ShouldSendHeartBeats || (LastHeartBeat == DateTime.MinValue))) {
return;
}
await RequestsSemaphore.WaitAsync().ConfigureAwait(false);
try {
- if ((DateTime.UtcNow < LastAnnouncementCheck.AddHours(MinAnnouncementCheckTTL)) && (ShouldSendHeartBeats || (LastHeartBeat == DateTime.MinValue))) {
+ if ((DateTime.UtcNow < LastAnnouncementCheck.AddMinutes(MinAnnouncementCheckTTL)) && (ShouldSendHeartBeats || (LastHeartBeat == DateTime.MinValue))) {
return;
}
@@ -188,6 +196,8 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
// This is actually network failure, so we'll stop sending heartbeats but not record it as valid check
ShouldSendHeartBeats = false;
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, nameof(tradeToken)));
+
return;
}
@@ -201,10 +211,10 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
return;
}
- HashSet inventory;
+ List inventory;
try {
- inventory = await Bot.ArchiWebHandler.GetInventoryAsync().Where(item => item.Tradable && acceptedMatchableTypes.Contains(item.Type)).ToHashSetAsync().ConfigureAwait(false);
+ inventory = await Bot.ArchiWebHandler.GetInventoryAsync().ToListAsync().ConfigureAwait(false);
} catch (HttpRequestException e) {
Bot.ArchiLogger.LogGenericWarningException(e);
@@ -224,28 +234,52 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
LastAnnouncementCheck = DateTime.UtcNow;
// This is actual inventory
- if (inventory.Count < MinItemsCount) {
+ if (inventory.Count(item => item.Tradable && acceptedMatchableTypes.Contains(item.Type)) < MinItemsCount) {
ShouldSendHeartBeats = false;
return;
}
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ListingAnnouncing, Bot.SteamID, nickname, inventory.Count));
+
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
- HttpStatusCode? response = await ArchiNet.AnnounceForListing(Bot, inventory, acceptedMatchableTypes, tradeToken!, nickname, avatarHash).ConfigureAwait(false);
+ HttpStatusCode? response = await Backend.AnnounceForListing(Bot, inventory, acceptedMatchableTypes, tradeToken!, nickname, avatarHash).ConfigureAwait(false);
if (!response.HasValue) {
return;
}
if (response.Value.IsClientErrorCode()) {
+ ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, response));
+
LastHeartBeat = DateTime.MinValue;
ShouldSendHeartBeats = false;
+ switch (response) {
+ case HttpStatusCode.Forbidden:
+ // ArchiNet told us to stop submitting data for now
+ LastAnnouncementCheck = DateTime.UtcNow.AddYears(1);
+
+ break;
+#if NETFRAMEWORK
+ case (HttpStatusCode) 429:
+#else
+ case HttpStatusCode.TooManyRequests:
+#endif
+
+ // ArchiNet told us to try again later
+ LastAnnouncementCheck = DateTime.UtcNow.AddDays(1);
+
+ break;
+ }
+
return;
}
LastHeartBeat = DateTime.UtcNow;
ShouldSendHeartBeats = true;
+
+ Bot.ArchiLogger.LogGenericInfo(ArchiSteamFarm.Localization.Strings.Success);
} finally {
RequestsSemaphore.Release();
}
@@ -261,7 +295,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
// Bot must have STM enabled in TradingPreferences
if (!Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher)) {
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.BotConfig.TradingPreferences)}: {Bot.BotConfig.TradingPreferences}"));
+ Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, $"{nameof(Bot.BotConfig.TradingPreferences)}: {Bot.BotConfig.TradingPreferences}"));
return false;
}
@@ -270,7 +304,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
bool? hasPublicInventory = await Bot.HasPublicInventory().ConfigureAwait(false);
if (hasPublicInventory != true) {
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.HasPublicInventory)}: {hasPublicInventory?.ToString() ?? "null"}"));
+ Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, $"{nameof(Bot.HasPublicInventory)}: {hasPublicInventory?.ToString() ?? "null"}"));
return hasPublicInventory;
}
@@ -281,14 +315,14 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
private async Task IsEligibleForMatching() {
// Bot must have ASF 2FA
if (!Bot.HasMobileAuthenticator) {
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.HasMobileAuthenticator)}: {Bot.HasMobileAuthenticator}"));
+ Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, $"{nameof(Bot.HasMobileAuthenticator)}: {Bot.HasMobileAuthenticator}"));
return false;
}
// Bot must have at least one accepted matchable type set
if ((Bot.BotConfig.MatchableTypes.Count == 0) || Bot.BotConfig.MatchableTypes.All(static type => !AcceptedMatchableTypes.Contains(type))) {
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.BotConfig.MatchableTypes)}: {string.Join(", ", Bot.BotConfig.MatchableTypes)}"));
+ Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, $"{nameof(Bot.BotConfig.MatchableTypes)}: {string.Join(", ", Bot.BotConfig.MatchableTypes)}"));
return false;
}
@@ -297,7 +331,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
bool? hasValidApiKey = await Bot.ArchiWebHandler.HasValidApiKey().ConfigureAwait(false);
if (hasValidApiKey != true) {
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, $"{nameof(Bot.ArchiWebHandler.HasValidApiKey)}: {hasValidApiKey?.ToString() ?? "null"}"));
+ Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, $"{nameof(Bot.ArchiWebHandler.HasValidApiKey)}: {hasValidApiKey?.ToString() ?? "null"}"));
return hasValidApiKey;
}
@@ -306,8 +340,16 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
private async void MatchActively(object? state = null) {
+ if (ASF.GlobalConfig == null) {
+ throw new InvalidOperationException(nameof(ASF.GlobalConfig));
+ }
+
+ if (!ASF.GlobalConfig.LicenseID.HasValue || (ASF.GlobalConfig.LicenseID == Guid.Empty)) {
+ throw new InvalidOperationException(nameof(ASF.GlobalConfig.LicenseID));
+ }
+
if (!Bot.IsConnectedAndLoggedOn || Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything) || !Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchActively) || (await IsEligibleForMatching().ConfigureAwait(false) != true)) {
- Bot.ArchiLogger.LogGenericTrace(Strings.ErrorAborted);
+ Bot.ArchiLogger.LogGenericTrace(ArchiSteamFarm.Localization.Strings.ErrorAborted);
return;
}
@@ -315,120 +357,125 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
HashSet acceptedMatchableTypes = Bot.BotConfig.MatchableTypes.Where(AcceptedMatchableTypes.Contains).ToHashSet();
if (acceptedMatchableTypes.Count == 0) {
- Bot.ArchiLogger.LogGenericTrace(Strings.ErrorAborted);
+ Bot.ArchiLogger.LogNullError(acceptedMatchableTypes);
return;
}
if (!await MatchActivelySemaphore.WaitAsync(0).ConfigureAwait(false)) {
- Bot.ArchiLogger.LogGenericTrace(Strings.ErrorAborted);
+ Bot.ArchiLogger.LogGenericTrace(ArchiSteamFarm.Localization.Strings.ErrorAborted);
return;
}
try {
- Bot.ArchiLogger.LogGenericTrace(Strings.Starting);
+ Bot.ArchiLogger.LogGenericInfo(ArchiSteamFarm.Localization.Strings.Starting);
- Dictionary? GivenAssetIDs, ISet? ReceivedAssetIDs)> triedSteamIDs = new();
+ string? tradeToken = await Bot.ArchiHandler.GetTradeToken().ConfigureAwait(false);
- bool shouldContinueMatching = true;
- bool tradedSomething = false;
+ if (string.IsNullOrEmpty(tradeToken)) {
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, nameof(tradeToken)));
- 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);
- }
-
- if (!Bot.IsConnectedAndLoggedOn || Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything) || !Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchActively) || (await IsEligibleForMatching().ConfigureAwait(false) != true)) {
- Bot.ArchiLogger.LogGenericTrace(Strings.ErrorAborted);
-
- break;
- }
-
-#pragma warning disable CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose
- using (await Bot.Actions.GetTradingLock().ConfigureAwait(false)) {
-#pragma warning restore CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose
- Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.ActivelyMatchingItems, i));
- (shouldContinueMatching, tradedSomething) = await MatchActivelyRound(acceptedMatchableTypes, triedSteamIDs).ConfigureAwait(false);
- Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.DoneActivelyMatchingItems, i));
- }
+ return;
}
- Bot.ArchiLogger.LogGenericTrace(Strings.Done);
+ HashSet ourInventory;
+
+ try {
+ ourInventory = await Bot.ArchiWebHandler.GetInventoryAsync().Where(item => acceptedMatchableTypes.Contains(item.Type) && !Bot.BotDatabase.MatchActivelyBlacklistAppIDs.Contains(item.RealAppID)).ToHashSetAsync().ConfigureAwait(false);
+ } catch (HttpRequestException e) {
+ Bot.ArchiLogger.LogGenericWarningException(e);
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, nameof(ourInventory)));
+
+ return;
+ } catch (Exception e) {
+ Bot.ArchiLogger.LogGenericException(e);
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, nameof(ourInventory)));
+
+ return;
+ }
+
+ if (ourInventory.Count == 0) {
+ Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.ErrorIsEmpty, nameof(ourInventory)));
+
+ return;
+ }
+
+ // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
+ (HttpStatusCode StatusCode, ImmutableHashSet Users)? response = await Backend.GetListedUsersForMatching(ASF.GlobalConfig.LicenseID.Value, Bot, ourInventory, acceptedMatchableTypes, tradeToken!).ConfigureAwait(false);
+
+ if (response == null) {
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, nameof(response)));
+
+ return;
+ }
+
+ if (!response.Value.StatusCode.IsSuccessCode()) {
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, response.Value.StatusCode));
+
+ return;
+ }
+
+ if (response.Value.Users.IsEmpty) {
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, nameof(response.Value.Users)));
+
+ return;
+ }
+
+#pragma warning disable CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose
+ using (await Bot.Actions.GetTradingLock().ConfigureAwait(false)) {
+#pragma warning restore CA2000 // False positive, we're actually wrapping it in the using clause below exactly for that purpose
+ Bot.ArchiLogger.LogGenericInfo(ArchiSteamFarm.Localization.Strings.Starting);
+ await MatchActivelyRound(response.Value.Users, ourInventory, acceptedMatchableTypes).ConfigureAwait(false);
+ }
+
+ Bot.ArchiLogger.LogGenericInfo(ArchiSteamFarm.Localization.Strings.Done);
} finally {
MatchActivelySemaphore.Release();
}
}
- private async Task<(bool ShouldContinueMatching, bool TradedSomething)> MatchActivelyRound(IReadOnlyCollection acceptedMatchableTypes, IDictionary? GivenAssetIDs, ISet? ReceivedAssetIDs)> triedSteamIDs) {
+ private async Task MatchActivelyRound(IReadOnlyCollection listedUsers, IReadOnlyCollection ourInventory, IReadOnlyCollection acceptedMatchableTypes) {
+ if ((listedUsers == null) || (listedUsers.Count == 0)) {
+ throw new ArgumentNullException(nameof(listedUsers));
+ }
+
+ if ((ourInventory == null) || (ourInventory.Count == 0)) {
+ throw new ArgumentNullException(nameof(ourInventory));
+ }
+
if ((acceptedMatchableTypes == null) || (acceptedMatchableTypes.Count == 0)) {
throw new ArgumentNullException(nameof(acceptedMatchableTypes));
}
- ArgumentNullException.ThrowIfNull(triedSteamIDs);
-
- HashSet ourInventory;
-
- try {
- ourInventory = await Bot.ArchiWebHandler.GetInventoryAsync().Where(item => acceptedMatchableTypes.Contains(item.Type) && !Bot.BotDatabase.MatchActivelyBlacklistAppIDs.Contains(item.RealAppID)).ToHashSetAsync().ConfigureAwait(false);
- } catch (HttpRequestException e) {
- Bot.ArchiLogger.LogGenericWarningException(e);
-
- return (false, false);
- } catch (Exception e) {
- Bot.ArchiLogger.LogGenericException(e);
-
- return (false, false);
- }
-
- if (ourInventory.Count == 0) {
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(ourInventory)));
-
- return (false, false);
- }
-
(Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), Dictionary> ourFullState, Dictionary<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity), Dictionary> ourTradableState) = Trading.GetDividedInventoryState(ourInventory);
if (Trading.IsEmptyForMatching(ourFullState, ourTradableState)) {
// User doesn't have any more dupes in the inventory
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, $"{nameof(ourFullState)} || {nameof(ourTradableState)}"));
+ Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.ErrorIsEmpty, $"{nameof(ourFullState)} || {nameof(ourTradableState)}"));
- return (false, false);
+ return;
}
- ImmutableHashSet? listedUsers = await ArchiNet.GetListedUsers(Bot).ConfigureAwait(false);
-
- if ((listedUsers == null) || (listedUsers.Count == 0)) {
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(listedUsers)));
-
- return (false, false);
- }
-
- byte maxTradeHoldDuration = ASF.GlobalConfig?.MaxTradeHoldDuration ?? GlobalConfig.DefaultMaxTradeHoldDuration;
- byte totalMatches = 0;
- bool rateLimited = false;
-
+ HashSet triedSteamIDs = new();
HashSet<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity)> skippedSetsThisRound = new();
- foreach (ArchiNet.ListedUser? listedUser in listedUsers.Where(listedUser => (listedUser.SteamID != Bot.SteamID) && acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && (!triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet? GivenAssetIDs, ISet? ReceivedAssetIDs) attempt) || (attempt.Tries < byte.MaxValue)) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderBy(listedUser => triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet? GivenAssetIDs, ISet? ReceivedAssetIDs) attempt) ? attempt.Tries : 0).ThenByDescending(static listedUser => listedUser.MatchEverything).ThenByDescending(static listedUser => listedUser.MatchEverything || (listedUser.ItemsCount < MaxItemsForFairBots)).ThenByDescending(static listedUser => listedUser.Score)) {
+ byte maxTradeHoldDuration = ASF.GlobalConfig?.MaxTradeHoldDuration ?? GlobalConfig.DefaultMaxTradeHoldDuration;
+
+ foreach (ListedUser listedUser in listedUsers.Where(listedUser => (listedUser.SteamID != Bot.SteamID) && !triedSteamIDs.Contains(listedUser.SteamID) && acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderByDescending(static listedUser => listedUser.MatchEverything).ThenBy(static listedUser => listedUser.Assets.Count)) {
HashSet<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity)> wantedSets = ourTradableState.Keys.Where(set => !skippedSetsThisRound.Contains(set) && listedUser.MatchableTypes.Contains(set.Type)).ToHashSet();
if (wantedSets.Count == 0) {
continue;
}
- if (++totalMatches > MaxMatchedBotsHard) {
- break;
- }
-
Bot.ArchiLogger.LogGenericTrace($"{listedUser.SteamID}...");
byte? tradeHoldDuration = await Bot.ArchiWebHandler.GetCombinedTradeHoldDurationAgainstUser(listedUser.SteamID, listedUser.TradeToken).ConfigureAwait(false);
switch (tradeHoldDuration) {
case null:
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(tradeHoldDuration)));
+ Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.ErrorIsEmpty, nameof(tradeHoldDuration)));
continue;
case > 0 when (tradeHoldDuration.Value > maxTradeHoldDuration) || (tradeHoldDuration.Value > listedUser.MaxTradeHoldDuration):
@@ -437,35 +484,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
continue;
}
- HashSet theirInventory;
-
- try {
- theirInventory = await Bot.ArchiWebHandler.GetInventoryAsync(listedUser.SteamID).Where(item => (!listedUser.MatchEverything || item.Tradable) && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity)) && ((tradeHoldDuration.Value == 0) || !(item.Type is Asset.EType.FoilTradingCard or Asset.EType.TradingCard && CardsFarmer.SalesBlacklist.Contains(item.RealAppID)))).ToHashSetAsync().ConfigureAwait(false);
- } catch (HttpRequestException e) {
- Bot.ArchiLogger.LogGenericWarningException(e);
-
-#if NETFRAMEWORK
- if (e.StatusCode == (HttpStatusCode) 429) {
-#else
- if (e.StatusCode == HttpStatusCode.TooManyRequests) {
-#endif
- rateLimited = true;
-
- break;
- }
-
- continue;
- } catch (Exception e) {
- Bot.ArchiLogger.LogGenericException(e);
-
- continue;
- }
-
- if (theirInventory.Count == 0) {
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(theirInventory)));
-
- continue;
- }
+ HashSet theirInventory = listedUser.Assets.Where(item => (!listedUser.MatchEverything || item.Tradable) && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity)) && ((tradeHoldDuration.Value == 0) || !(item.Type is Asset.EType.FoilTradingCard or Asset.EType.TradingCard && CardsFarmer.SalesBlacklist.Contains(item.RealAppID)))).Select(static asset => asset.ToAsset()).ToHashSet();
HashSet<(uint RealAppID, Asset.EType Type, Asset.ERarity Rarity)> skippedSetsThisUser = new();
@@ -500,7 +519,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
if (!ourFullSet.TryGetValue(classID, out uint fullAmount) || (fullAmount == 0) || (fullAmount < amount)) {
Bot.ArchiLogger.LogNullError(fullAmount);
- return (false, skippedSetsThisRound.Count > 0);
+ return;
}
if (fullAmount > amount) {
@@ -512,7 +531,7 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
if (!ourTradableSet.TryGetValue(classID, out uint tradableAmount) || (tradableAmount == 0) || (tradableAmount < amount)) {
Bot.ArchiLogger.LogNullError(tradableAmount);
- return (false, skippedSetsThisRound.Count > 0);
+ return;
}
if (fullAmount > amount) {
@@ -625,40 +644,27 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
if (skippedSetsThisTrade.Count == 0) {
- Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(skippedSetsThisTrade)));
+ Bot.ArchiLogger.LogGenericTrace(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.ErrorIsEmpty, nameof(skippedSetsThisTrade)));
break;
}
// Remove the items from inventories
HashSet itemsToGive = Trading.GetTradableItemsFromInventory(ourInventory, classIDsToGive);
- HashSet itemsToReceive = Trading.GetTradableItemsFromInventory(theirInventory, classIDsToReceive);
+ HashSet itemsToReceive = Trading.GetTradableItemsFromInventory(theirInventory, classIDsToReceive, true);
if ((itemsToGive.Count != itemsToReceive.Count) || !Trading.IsFairExchange(itemsToGive, itemsToReceive)) {
// Failsafe
- Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, Strings.ErrorAborted));
+ Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, ArchiSteamFarm.Localization.Strings.ErrorAborted));
- return (false, skippedSetsThisRound.Count > 0);
+ return;
}
- if (triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet? GivenAssetIDs, ISet? ReceivedAssetIDs) previousAttempt)) {
- if ((previousAttempt.GivenAssetIDs == null) || (previousAttempt.ReceivedAssetIDs == null) || (itemsToGive.Select(static item => item.AssetID).All(previousAttempt.GivenAssetIDs.Contains) && itemsToReceive.Select(static item => item.AssetID).All(previousAttempt.ReceivedAssetIDs.Contains))) {
- // This user didn't respond in our previous round, avoid him for remaining ones
- triedSteamIDs[listedUser.SteamID] = (byte.MaxValue, previousAttempt.GivenAssetIDs, previousAttempt.ReceivedAssetIDs);
+ triedSteamIDs.Add(listedUser.SteamID);
- break;
- }
+ Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.MatchingFound, itemsToReceive.Count, listedUser.SteamID, listedUser.Nickname));
- previousAttempt.GivenAssetIDs.UnionWith(itemsToGive.Select(static item => item.AssetID));
- previousAttempt.ReceivedAssetIDs.UnionWith(itemsToReceive.Select(static item => item.AssetID));
- } else {
- previousAttempt.GivenAssetIDs = new HashSet(itemsToGive.Select(static item => item.AssetID));
- previousAttempt.ReceivedAssetIDs = new HashSet(itemsToReceive.Select(static item => item.AssetID));
- }
-
- triedSteamIDs[listedUser.SteamID] = (++previousAttempt.Tries, previousAttempt.GivenAssetIDs, previousAttempt.ReceivedAssetIDs);
-
- Bot.ArchiLogger.LogGenericTrace($"{Bot.SteamID} <- {string.Join(", ", itemsToReceive.Select(static item => $"{item.RealAppID}/{item.Type}-{item.ClassID} #{item.Amount}"))} | {string.Join(", ", itemsToGive.Select(static item => $"{item.RealAppID}/{item.Type}-{item.ClassID} #{item.Amount}"))} -> {listedUser.SteamID}");
+ Bot.ArchiLogger.LogGenericTrace($"{Bot.SteamID} <- {string.Join(", ", itemsToReceive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} | {string.Join(", ", itemsToGive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} -> {listedUser.SteamID}");
(bool success, HashSet? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, true).ConfigureAwait(false);
@@ -666,14 +672,14 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
(bool twoFactorSuccess, _, _) = await Bot.Actions.HandleTwoFactorAuthenticationConfirmations(true, Confirmation.EType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false);
if (!twoFactorSuccess) {
- Bot.ArchiLogger.LogGenericTrace(Strings.WarningFailed);
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, nameof(twoFactorSuccess)));
- return (false, skippedSetsThisRound.Count > 0);
+ return;
}
}
if (!success) {
- Bot.ArchiLogger.LogGenericTrace(Strings.WarningFailed);
+ Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.TradeOfferFailed, listedUser.SteamID, listedUser.Nickname));
break;
}
@@ -682,15 +688,10 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
theirInventory.UnionWith(itemsToGive);
skippedSetsThisUser.UnionWith(skippedSetsThisTrade);
- Bot.ArchiLogger.LogGenericTrace(Strings.Success);
+ Bot.ArchiLogger.LogGenericInfo(ArchiSteamFarm.Localization.Strings.Success);
}
if (skippedSetsThisUser.Count == 0) {
- if (skippedSetsThisRound.Count == 0) {
- // If we didn't find any match on clean round, this user isn't going to have anything interesting for us anytime soon
- triedSteamIDs[listedUser.SteamID] = (byte.MaxValue, null, null);
- }
-
continue;
}
@@ -711,8 +712,5 @@ internal sealed class RemoteCommunication : IAsyncDisposable, IDisposable {
}
Bot.ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.ActivelyMatchingItemsRound, skippedSetsThisRound.Count));
-
- // 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 (!rateLimited && (totalMatches > 0) && ((skippedSetsThisRound.Count > 0) || triedSteamIDs.Values.All(static data => data.Tries < 2)), skippedSetsThisRound.Count > 0);
}
}
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/AnnouncementRequest.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/AnnouncementRequest.cs
new file mode 100644
index 000000000..62c27a23e
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/AnnouncementRequest.cs
@@ -0,0 +1,106 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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 System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using ArchiSteamFarm.Steam.Data;
+using ArchiSteamFarm.Steam.Storage;
+using JetBrains.Annotations;
+using Newtonsoft.Json;
+using SteamKit2;
+
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Requests;
+
+internal sealed class AnnouncementRequest {
+ [JsonProperty]
+ internal readonly string? AvatarHash;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly Guid Guid;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ImmutableHashSet Inventory;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ImmutableHashSet MatchableTypes;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly bool MatchEverything;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly byte MaxTradeHoldDuration;
+
+ [JsonProperty]
+ internal readonly string? Nickname;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ulong SteamID;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly string TradeToken;
+
+ internal AnnouncementRequest(Guid guid, ulong steamID, string tradeToken, IReadOnlyList inventory, IReadOnlyCollection matchableTypes, bool matchEverything, byte maxTradeHoldDuration, string? nickname = null, string? avatarHash = null) {
+ if (guid == Guid.Empty) {
+ throw new ArgumentOutOfRangeException(nameof(guid));
+ }
+
+ if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
+ throw new ArgumentOutOfRangeException(nameof(steamID));
+ }
+
+ if (string.IsNullOrEmpty(tradeToken)) {
+ throw new ArgumentNullException(nameof(tradeToken));
+ }
+
+ if (tradeToken.Length != BotConfig.SteamTradeTokenLength) {
+ throw new ArgumentOutOfRangeException(nameof(tradeToken));
+ }
+
+ if ((inventory == null) || (inventory.Count == 0)) {
+ throw new ArgumentNullException(nameof(inventory));
+ }
+
+ if ((matchableTypes == null) || (matchableTypes.Count == 0)) {
+ throw new ArgumentNullException(nameof(matchableTypes));
+ }
+
+ uint index = 0;
+
+ Guid = guid;
+ SteamID = steamID;
+ TradeToken = tradeToken;
+ Inventory = inventory.Select(asset => new AssetForListing(asset, index++)).ToImmutableHashSet();
+ MatchableTypes = matchableTypes.ToImmutableHashSet();
+ MatchEverything = matchEverything;
+ MaxTradeHoldDuration = maxTradeHoldDuration;
+
+ Nickname = nickname;
+ AvatarHash = avatarHash;
+ }
+
+ [UsedImplicitly]
+ public bool ShouldSerializeAvatarHash() => !string.IsNullOrEmpty(AvatarHash);
+
+ [UsedImplicitly]
+ public bool ShouldSerializeNickname() => !string.IsNullOrEmpty(Nickname);
+}
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/AssetForListing.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/AssetForListing.cs
new file mode 100644
index 000000000..ffce9056e
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/AssetForListing.cs
@@ -0,0 +1,37 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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 ArchiSteamFarm.Steam.Data;
+using Newtonsoft.Json;
+
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Requests;
+
+internal sealed class AssetForListing : AssetInInventory {
+ [JsonProperty(Required = Required.Always)]
+ internal readonly uint Index;
+
+ internal AssetForListing(Asset asset, uint index) : base(asset) {
+ ArgumentNullException.ThrowIfNull(asset);
+
+ Index = index;
+ }
+}
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/AssetInInventory.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/AssetInInventory.cs
new file mode 100644
index 000000000..2381bba11
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/AssetInInventory.cs
@@ -0,0 +1,68 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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 ArchiSteamFarm.Steam.Data;
+using Newtonsoft.Json;
+
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Requests;
+
+internal class AssetInInventory {
+ [JsonProperty(Required = Required.Always)]
+ internal readonly uint Amount;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ulong AssetID;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ulong ClassID;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly Asset.ERarity Rarity;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly uint RealAppID;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly bool Tradable;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly Asset.EType Type;
+
+ internal AssetInInventory(Asset asset) {
+ ArgumentNullException.ThrowIfNull(asset);
+
+ AssetID = asset.AssetID;
+ Amount = asset.Amount;
+
+ ClassID = asset.ClassID;
+ Tradable = asset.Tradable;
+
+ RealAppID = asset.RealAppID;
+ Type = asset.Type;
+ Rarity = asset.Rarity;
+ }
+
+ [JsonConstructor]
+ private AssetInInventory() { }
+
+ internal Asset ToAsset() => new(Asset.SteamAppID, Asset.SteamCommunityContextID, ClassID, Amount, tradable: Tradable, assetID: AssetID, realAppID: RealAppID, type: Type, rarity: Rarity);
+}
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/HeartBeatRequest.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/HeartBeatRequest.cs
new file mode 100644
index 000000000..e20b2e2dd
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/HeartBeatRequest.cs
@@ -0,0 +1,47 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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 Newtonsoft.Json;
+using SteamKit2;
+
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Requests;
+
+internal sealed class HeartBeatRequest {
+ [JsonProperty(Required = Required.Always)]
+ internal readonly Guid Guid;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ulong SteamID;
+
+ internal HeartBeatRequest(Guid guid, ulong steamID) {
+ if (guid == Guid.Empty) {
+ throw new ArgumentOutOfRangeException(nameof(guid));
+ }
+
+ if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
+ throw new ArgumentOutOfRangeException(nameof(steamID));
+ }
+
+ Guid = guid;
+ SteamID = steamID;
+ }
+}
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/InventoriesRequest.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/InventoriesRequest.cs
new file mode 100644
index 000000000..fb4d2a07d
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Requests/InventoriesRequest.cs
@@ -0,0 +1,84 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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 System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using ArchiSteamFarm.Steam.Data;
+using ArchiSteamFarm.Steam.Storage;
+using Newtonsoft.Json;
+using SteamKit2;
+
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Requests;
+
+internal sealed class InventoriesRequest {
+ [JsonProperty(Required = Required.Always)]
+ internal readonly Guid Guid;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ImmutableHashSet Inventory;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ImmutableHashSet MatchableTypes;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly byte MaxTradeHoldDuration;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ulong SteamID;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly string TradeToken;
+
+ internal InventoriesRequest(Guid guid, ulong steamID, string tradeToken, IReadOnlyCollection inventory, IReadOnlyCollection matchableTypes, byte maxTradeHoldDuration) {
+ if (guid == Guid.Empty) {
+ throw new ArgumentOutOfRangeException(nameof(guid));
+ }
+
+ if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
+ throw new ArgumentOutOfRangeException(nameof(steamID));
+ }
+
+ if (string.IsNullOrEmpty(tradeToken)) {
+ throw new ArgumentNullException(nameof(tradeToken));
+ }
+
+ if (tradeToken.Length != BotConfig.SteamTradeTokenLength) {
+ throw new ArgumentOutOfRangeException(nameof(tradeToken));
+ }
+
+ if ((inventory == null) || (inventory.Count == 0)) {
+ throw new ArgumentNullException(nameof(inventory));
+ }
+
+ if ((matchableTypes == null) || (matchableTypes.Count == 0)) {
+ throw new ArgumentNullException(nameof(matchableTypes));
+ }
+
+ Guid = guid;
+ SteamID = steamID;
+ TradeToken = tradeToken;
+ Inventory = inventory.Select(static asset => new AssetInInventory(asset)).ToImmutableHashSet();
+ MatchableTypes = matchableTypes.ToImmutableHashSet();
+ MaxTradeHoldDuration = maxTradeHoldDuration;
+ }
+}
diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Responses/ListedUser.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Responses/ListedUser.cs
new file mode 100644
index 000000000..084f6ac6f
--- /dev/null
+++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/Responses/ListedUser.cs
@@ -0,0 +1,65 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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.Immutable;
+using System.Diagnostics.CodeAnalysis;
+using ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Requests;
+using ArchiSteamFarm.Steam.Data;
+using Newtonsoft.Json;
+
+namespace ArchiSteamFarm.OfficialPlugins.ItemsMatcher.Responses;
+
+#pragma warning disable CA1812 // False positive, the class is used during json deserialization
+[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
+internal sealed class ListedUser {
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ImmutableHashSet Assets = ImmutableHashSet.Empty;
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ImmutableHashSet MatchableTypes = ImmutableHashSet.Empty;
+
+#pragma warning disable CS0649 // False positive, the field is used during json deserialization
+ [JsonProperty(Required = Required.Always)]
+ internal readonly bool MatchEverything;
+#pragma warning restore CS0649 // False positive, the field is used during json deserialization
+
+#pragma warning disable CS0649 // False positive, the field is used during json deserialization
+ [JsonProperty(Required = Required.Always)]
+ internal readonly byte MaxTradeHoldDuration;
+#pragma warning restore CS0649 // False positive, the field is used during json deserialization
+
+#pragma warning disable CS0649 // False positive, the field is used during json deserialization
+ [JsonProperty(Required = Required.AllowNull)]
+ internal readonly string? Nickname;
+#pragma warning restore CS0649 // False positive, the field is used during json deserialization
+
+#pragma warning disable CS0649 // False positive, the field is used during json deserialization
+ [JsonProperty(Required = Required.Always)]
+ internal readonly ulong SteamID;
+#pragma warning restore CS0649 // False positive, the field is used during json deserialization
+
+ [JsonProperty(Required = Required.Always)]
+ internal readonly string TradeToken = "";
+
+ [JsonConstructor]
+ private ListedUser() { }
+}
+#pragma warning restore CA1812 // False positive, the class is used during json deserialization
diff --git a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SteamTokenDumperPlugin.cs b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SteamTokenDumperPlugin.cs
index 506daaaba..1e1586c0b 100644
--- a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SteamTokenDumperPlugin.cs
+++ b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SteamTokenDumperPlugin.cs
@@ -545,27 +545,26 @@ internal sealed class SteamTokenDumperPlugin : OfficialPlugin, IASF, IBot, IBotC
ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, ArchiSteamFarm.Localization.Strings.WarningFailedWithError, response.StatusCode));
switch (response.StatusCode) {
- // SteamDB told us to stop submitting data for now
case HttpStatusCode.Forbidden:
+ // SteamDB told us to stop submitting data for now
// ReSharper disable once SuspiciousLockOverSynchronizationPrimitive - this is not a mistake, we need extra synchronization, and we can re-use the semaphore object for that
lock (SubmissionSemaphore) {
SubmissionTimer.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
}
break;
-
- // SteamDB told us to reset our cache
case HttpStatusCode.Conflict:
+ // SteamDB told us to reset our cache
GlobalCache.Reset(true);
break;
-
- // SteamDB told us to try again later
#if NETFRAMEWORK
case (HttpStatusCode) 429:
#else
case HttpStatusCode.TooManyRequests:
#endif
+
+ // SteamDB told us to try again later
#pragma warning disable CA5394 // This call isn't used in a security-sensitive manner
TimeSpan startIn = TimeSpan.FromMinutes(Random.Shared.Next(SharedInfo.MinimumMinutesBeforeFirstUpload, SharedInfo.MaximumMinutesBeforeFirstUpload));
#pragma warning restore CA5394 // This call isn't used in a security-sensitive manner
diff --git a/ArchiSteamFarm.sln b/ArchiSteamFarm.sln
index 898a6b24f..83aca52e9 100644
--- a/ArchiSteamFarm.sln
+++ b/ArchiSteamFarm.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.6.30114.105
@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchiSteamFarm.CustomPlugin
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper", "ArchiSteamFarm.OfficialPlugins.SteamTokenDumper\ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.csproj", "{324E42B1-3C5D-421D-A600-1BEEE7AF401A}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchiSteamFarm.OfficialPlugins.ItemsMatcher", "ArchiSteamFarm.OfficialPlugins.ItemsMatcher\ArchiSteamFarm.OfficialPlugins.ItemsMatcher.csproj", "{A8BA3425-2EE4-4333-9905-8867EDFE327F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -53,5 +55,11 @@ Global
{324E42B1-3C5D-421D-A600-1BEEE7AF401A}.DebugFast|Any CPU.Build.0 = DebugFast|Any CPU
{324E42B1-3C5D-421D-A600-1BEEE7AF401A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{324E42B1-3C5D-421D-A600-1BEEE7AF401A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A8BA3425-2EE4-4333-9905-8867EDFE327F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A8BA3425-2EE4-4333-9905-8867EDFE327F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A8BA3425-2EE4-4333-9905-8867EDFE327F}.DebugFast|Any CPU.ActiveCfg = Debug|Any CPU
+ {A8BA3425-2EE4-4333-9905-8867EDFE327F}.DebugFast|Any CPU.Build.0 = Debug|Any CPU
+ {A8BA3425-2EE4-4333-9905-8867EDFE327F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A8BA3425-2EE4-4333-9905-8867EDFE327F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/ArchiSteamFarm/AssemblyInfo.cs b/ArchiSteamFarm/AssemblyInfo.cs
index 6203f9f75..d2227e74d 100644
--- a/ArchiSteamFarm/AssemblyInfo.cs
+++ b/ArchiSteamFarm/AssemblyInfo.cs
@@ -26,8 +26,10 @@ using System.Runtime.CompilerServices;
#if ASF_SIGNED_BUILD
[assembly: InternalsVisibleTo("ArchiSteamFarm.Tests, PublicKey=002400000480000014020000060200000024000052534131001000000100010099f0e5961ec7497fd7de1cba2b8c5eff3b18c1faf3d7a8d56e063359c7f928b54b14eae24d23d9d3c1a5db7ceca82edb6956d43e8ea2a0b7223e6e6836c0b809de43fde69bf33fba73cf669e71449284d477333d4b6e54fb69f7b6c4b4811b8fe26e88975e593cffc0e321490a50500865c01e50ab87c8a943b2a788af47dc20f2b860062b7b6df25477e471a744485a286b435cea2df3953cbb66febd8db73f3ccb4588886373141d200f749ba40bb11926b668cc15f328412dd0b0b835909229985336eb4a34f47925558dc6dc3910ea09c1aad5c744833f26ad9de727559d393526a7a29b3383de87802a034ead8ecc2d37340a5fa9b406774446256337d77e3c9e8486b5e732097e238312deaf5b4efcc04df8ecb986d90ee12b4a8a9a00319cc25cb91fd3e36a3cc39e501f83d14eb1e1a6fa6a1365483d99f4cefad1ea5dec204dad958e2a9a93add19781a8aa7bac71747b11d156711eafd1e873e19836eb573fa5cde284739df09b658ed40c56c7b5a7596840774a7065864e6c2af7b5a8bf7a2d238de83d77891d98ef5a4a58248c655a1c7c97c99e01d9928dc60c629eeb523356dc3686e3f9a1a30ffcd0268cd03718292f21d839fce741f4c1163001ab5b654c37d862998962a05e8028e061c611384772777ef6a49b00ebb4f228308e61b2afe408b33db2d82c4f385e26d7438ec0a183c64eeca4138cbc3dc2")]
+[assembly: InternalsVisibleTo("ArchiSteamFarm.OfficialPlugins.ItemsMatcher, PublicKey=002400000480000014020000060200000024000052534131001000000100010099f0e5961ec7497fd7de1cba2b8c5eff3b18c1faf3d7a8d56e063359c7f928b54b14eae24d23d9d3c1a5db7ceca82edb6956d43e8ea2a0b7223e6e6836c0b809de43fde69bf33fba73cf669e71449284d477333d4b6e54fb69f7b6c4b4811b8fe26e88975e593cffc0e321490a50500865c01e50ab87c8a943b2a788af47dc20f2b860062b7b6df25477e471a744485a286b435cea2df3953cbb66febd8db73f3ccb4588886373141d200f749ba40bb11926b668cc15f328412dd0b0b835909229985336eb4a34f47925558dc6dc3910ea09c1aad5c744833f26ad9de727559d393526a7a29b3383de87802a034ead8ecc2d37340a5fa9b406774446256337d77e3c9e8486b5e732097e238312deaf5b4efcc04df8ecb986d90ee12b4a8a9a00319cc25cb91fd3e36a3cc39e501f83d14eb1e1a6fa6a1365483d99f4cefad1ea5dec204dad958e2a9a93add19781a8aa7bac71747b11d156711eafd1e873e19836eb573fa5cde284739df09b658ed40c56c7b5a7596840774a7065864e6c2af7b5a8bf7a2d238de83d77891d98ef5a4a58248c655a1c7c97c99e01d9928dc60c629eeb523356dc3686e3f9a1a30ffcd0268cd03718292f21d839fce741f4c1163001ab5b654c37d862998962a05e8028e061c611384772777ef6a49b00ebb4f228308e61b2afe408b33db2d82c4f385e26d7438ec0a183c64eeca4138cbc3dc2")]
[assembly: InternalsVisibleTo("ArchiSteamFarm.OfficialPlugins.SteamTokenDumper, PublicKey=002400000480000014020000060200000024000052534131001000000100010099f0e5961ec7497fd7de1cba2b8c5eff3b18c1faf3d7a8d56e063359c7f928b54b14eae24d23d9d3c1a5db7ceca82edb6956d43e8ea2a0b7223e6e6836c0b809de43fde69bf33fba73cf669e71449284d477333d4b6e54fb69f7b6c4b4811b8fe26e88975e593cffc0e321490a50500865c01e50ab87c8a943b2a788af47dc20f2b860062b7b6df25477e471a744485a286b435cea2df3953cbb66febd8db73f3ccb4588886373141d200f749ba40bb11926b668cc15f328412dd0b0b835909229985336eb4a34f47925558dc6dc3910ea09c1aad5c744833f26ad9de727559d393526a7a29b3383de87802a034ead8ecc2d37340a5fa9b406774446256337d77e3c9e8486b5e732097e238312deaf5b4efcc04df8ecb986d90ee12b4a8a9a00319cc25cb91fd3e36a3cc39e501f83d14eb1e1a6fa6a1365483d99f4cefad1ea5dec204dad958e2a9a93add19781a8aa7bac71747b11d156711eafd1e873e19836eb573fa5cde284739df09b658ed40c56c7b5a7596840774a7065864e6c2af7b5a8bf7a2d238de83d77891d98ef5a4a58248c655a1c7c97c99e01d9928dc60c629eeb523356dc3686e3f9a1a30ffcd0268cd03718292f21d839fce741f4c1163001ab5b654c37d862998962a05e8028e061c611384772777ef6a49b00ebb4f228308e61b2afe408b33db2d82c4f385e26d7438ec0a183c64eeca4138cbc3dc2")]
#else
[assembly: InternalsVisibleTo("ArchiSteamFarm.Tests")]
+[assembly: InternalsVisibleTo("ArchiSteamFarm.OfficialPlugins.ItemsMatcher")]
[assembly: InternalsVisibleTo("ArchiSteamFarm.OfficialPlugins.SteamTokenDumper")]
#endif
diff --git a/ArchiSteamFarm/Core/ArchiNet.cs b/ArchiSteamFarm/Core/ArchiNet.cs
index 69f7f92a2..9318f40c8 100644
--- a/ArchiSteamFarm/Core/ArchiNet.cs
+++ b/ArchiSteamFarm/Core/ArchiNet.cs
@@ -20,65 +20,14 @@
// limitations under the License.
using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.Linq;
-using System.Net;
using System.Threading.Tasks;
-using ArchiSteamFarm.Localization;
-using ArchiSteamFarm.Steam;
-using ArchiSteamFarm.Steam.Data;
-using ArchiSteamFarm.Steam.Storage;
-using ArchiSteamFarm.Storage;
-using ArchiSteamFarm.Web;
+using ArchiSteamFarm.IPC.Responses;
using ArchiSteamFarm.Web.Responses;
-using Newtonsoft.Json;
namespace ArchiSteamFarm.Core;
internal static class ArchiNet {
- private static Uri URL => new("https://asf.JustArchi.net");
-
- internal static async Task AnnounceForListing(Bot bot, IReadOnlyCollection inventory, IReadOnlyCollection acceptedMatchableTypes, string tradeToken, string? nickname = null, string? avatarHash = null) {
- ArgumentNullException.ThrowIfNull(bot);
-
- if ((inventory == null) || (inventory.Count == 0)) {
- throw new ArgumentNullException(nameof(inventory));
- }
-
- if ((acceptedMatchableTypes == null) || (acceptedMatchableTypes.Count == 0)) {
- throw new ArgumentNullException(nameof(acceptedMatchableTypes));
- }
-
- if (string.IsNullOrEmpty(tradeToken)) {
- throw new ArgumentNullException(nameof(tradeToken));
- }
-
- if (tradeToken.Length != BotConfig.SteamTradeTokenLength) {
- throw new ArgumentOutOfRangeException(nameof(tradeToken));
- }
-
- Uri request = new(URL, "/Api/Announce");
-
- Dictionary data = new(10, StringComparer.Ordinal) {
- { "AvatarHash", avatarHash ?? "" },
- { "GamesCount", inventory.Select(static item => item.RealAppID).Distinct().Count().ToString(CultureInfo.InvariantCulture) },
- { "Guid", (ASF.GlobalDatabase?.Identifier ?? Guid.NewGuid()).ToString("N") },
- { "ItemsCount", inventory.Count.ToString(CultureInfo.InvariantCulture) },
- { "MatchableTypes", JsonConvert.SerializeObject(acceptedMatchableTypes) },
- { "MatchEverything", bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything) ? "1" : "0" },
- { "MaxTradeHoldDuration", (ASF.GlobalConfig?.MaxTradeHoldDuration ?? GlobalConfig.DefaultMaxTradeHoldDuration).ToString(CultureInfo.InvariantCulture) },
- { "Nickname", nickname ?? "" },
- { "SteamID", bot.SteamID.ToString(CultureInfo.InvariantCulture) },
- { "TradeToken", tradeToken }
- };
-
- BasicResponse? response = await bot.ArchiWebHandler.WebBrowser.UrlPost(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors).ConfigureAwait(false);
-
- return response?.StatusCode;
- }
+ internal static Uri URL => new("https://asf.JustArchi.net");
internal static async Task FetchBuildChecksum(Version version, string variant) {
ArgumentNullException.ThrowIfNull(version);
@@ -93,177 +42,12 @@ internal static class ArchiNet {
Uri request = new(URL, $"/Api/Checksum/{version}/{variant}");
- ObjectResponse? response = await ASF.WebBrowser.UrlGetToJsonObject(request).ConfigureAwait(false);
+ ObjectResponse>? response = await ASF.WebBrowser.UrlGetToJsonObject>(request).ConfigureAwait(false);
if (response?.Content == null) {
return null;
}
- return response.Content.Checksum ?? "";
- }
-
- internal static async Task?> GetListedUsers(Bot bot) {
- ArgumentNullException.ThrowIfNull(bot);
-
- Uri request = new(URL, "/Api/Bots");
-
- ObjectResponse>? response = await bot.ArchiWebHandler.WebBrowser.UrlGetToJsonObject>(request).ConfigureAwait(false);
-
- return response?.Content;
- }
-
- internal static async Task HeartBeatForListing(Bot bot) {
- ArgumentNullException.ThrowIfNull(bot);
-
- Uri request = new(URL, "/Api/HeartBeat");
-
- Dictionary data = new(2, StringComparer.Ordinal) {
- { "Guid", (ASF.GlobalDatabase?.Identifier ?? Guid.NewGuid()).ToString("N") },
- { "SteamID", bot.SteamID.ToString(CultureInfo.InvariantCulture) }
- };
-
- BasicResponse? response = await bot.ArchiWebHandler.WebBrowser.UrlPost(request, data: data, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors).ConfigureAwait(false);
-
- return response?.StatusCode;
- }
-
- [SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
- internal sealed class ListedUser {
- [JsonProperty("items_count", Required = Required.Always)]
- internal readonly ushort ItemsCount;
-
- internal readonly HashSet MatchableTypes = new();
-
- [JsonProperty("max_trade_hold_duration", Required = Required.Always)]
- internal readonly byte MaxTradeHoldDuration;
-
- [JsonProperty("steam_id", Required = Required.Always)]
- internal readonly ulong SteamID;
-
- [JsonProperty("trade_token", Required = Required.Always)]
- internal readonly string TradeToken = "";
-
- internal float Score => GamesCount / (float) ItemsCount;
-
-#pragma warning disable CS0649 // False positive, it's a field set during json deserialization
- [JsonProperty("games_count", Required = Required.Always)]
- private readonly ushort GamesCount;
-#pragma warning restore CS0649 // False positive, it's a field set during json deserialization
-
- internal bool MatchEverything { get; private set; }
-
- [JsonProperty("matchable_backgrounds", Required = Required.Always)]
- private byte MatchableBackgroundsNumber {
- set {
- switch (value) {
- case 0:
- MatchableTypes.Remove(Asset.EType.ProfileBackground);
-
- break;
- case 1:
- MatchableTypes.Add(Asset.EType.ProfileBackground);
-
- break;
- default:
- ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(value), value));
-
- return;
- }
- }
- }
-
- [JsonProperty("matchable_cards", Required = Required.Always)]
- private byte MatchableCardsNumber {
- set {
- switch (value) {
- case 0:
- MatchableTypes.Remove(Asset.EType.TradingCard);
-
- break;
- case 1:
- MatchableTypes.Add(Asset.EType.TradingCard);
-
- break;
- default:
- ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(value), value));
-
- return;
- }
- }
- }
-
- [JsonProperty("matchable_emoticons", Required = Required.Always)]
- private byte MatchableEmoticonsNumber {
- set {
- switch (value) {
- case 0:
- MatchableTypes.Remove(Asset.EType.Emoticon);
-
- break;
- case 1:
- MatchableTypes.Add(Asset.EType.Emoticon);
-
- break;
- default:
- ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(value), value));
-
- return;
- }
- }
- }
-
- [JsonProperty("matchable_foil_cards", Required = Required.Always)]
- private byte MatchableFoilCardsNumber {
- set {
- switch (value) {
- case 0:
- MatchableTypes.Remove(Asset.EType.FoilTradingCard);
-
- break;
- case 1:
- MatchableTypes.Add(Asset.EType.FoilTradingCard);
-
- break;
- default:
- ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(value), value));
-
- return;
- }
- }
- }
-
- [JsonProperty("match_everything", Required = Required.Always)]
- private byte MatchEverythingNumber {
- set {
- switch (value) {
- case 0:
- MatchEverything = false;
-
- break;
- case 1:
- MatchEverything = true;
-
- break;
- default:
- ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(value), value));
-
- return;
- }
- }
- }
-
- [JsonConstructor]
- private ListedUser() { }
- }
-
- [SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
- private sealed class ChecksumResponse {
-#pragma warning disable CS0649 // False positive, the field is used during json deserialization
- [JsonProperty("checksum", Required = Required.AllowNull)]
- internal readonly string? Checksum;
-#pragma warning restore CS0649 // False positive, the field is used during json deserialization
-
- [JsonConstructor]
- private ChecksumResponse() { }
+ return response.Content.Result ?? "";
}
}
diff --git a/ArchiSteamFarm/IPC/Responses/GenericResponse.cs b/ArchiSteamFarm/IPC/Responses/GenericResponse.cs
index d3c119366..0706c789e 100644
--- a/ArchiSteamFarm/IPC/Responses/GenericResponse.cs
+++ b/ArchiSteamFarm/IPC/Responses/GenericResponse.cs
@@ -39,6 +39,9 @@ public sealed class GenericResponse : GenericResponse where T : class {
public GenericResponse(bool success, string? message) : base(success, message) { }
public GenericResponse(bool success, T? result) : base(success) => Result = result;
public GenericResponse(bool success, string? message, T? result) : base(success, message) => Result = result;
+
+ [JsonConstructor]
+ private GenericResponse() { }
}
public class GenericResponse {
@@ -49,7 +52,7 @@ public class GenericResponse {
/// This property will provide exact reason for majority of expected failures.
///
[JsonProperty]
- public string Message { get; private set; }
+ public string? Message { get; private set; }
///
/// Boolean type that specifies if the request has succeeded.
@@ -64,4 +67,7 @@ public class GenericResponse {
// ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework
Message = !string.IsNullOrEmpty(message) ? message! : success ? "OK" : Strings.WarningFailed;
}
+
+ [JsonConstructor]
+ protected GenericResponse() { }
}
diff --git a/ArchiSteamFarm/Localization/Strings.Designer.cs b/ArchiSteamFarm/Localization/Strings.Designer.cs
index bceea327e..3e095912b 100644
--- a/ArchiSteamFarm/Localization/Strings.Designer.cs
+++ b/ArchiSteamFarm/Localization/Strings.Designer.cs
@@ -11,46 +11,32 @@ namespace ArchiSteamFarm.Localization {
using System;
- ///
- /// A strongly-typed resource class, for looking up localized strings, etc.
- ///
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Strings {
- private static global::System.Resources.ResourceManager resourceMan;
+ private static System.Resources.ResourceManager resourceMan;
- private static global::System.Globalization.CultureInfo resourceCulture;
+ private static System.Globalization.CultureInfo resourceCulture;
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Strings() {
}
- ///
- /// Returns the cached ResourceManager instance used by this class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- public static global::System.Resources.ResourceManager ResourceManager {
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static System.Resources.ResourceManager ResourceManager {
get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ArchiSteamFarm.Localization.Strings", typeof(Strings).Assembly);
+ if (object.Equals(null, resourceMan)) {
+ System.Resources.ResourceManager temp = new System.Resources.ResourceManager("ArchiSteamFarm.Localization.Strings", typeof(Strings).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
- ///
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- public static global::System.Globalization.CultureInfo Culture {
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
@@ -59,1753 +45,1167 @@ namespace ArchiSteamFarm.Localization {
}
}
- ///
- /// Looks up a localized string similar to Accepting trade: {0}.
- ///
public static string AcceptingTrade {
get {
return ResourceManager.GetString("AcceptingTrade", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Matching Steam items, round #{0}....
- ///
- public static string ActivelyMatchingItems {
- get {
- return ResourceManager.GetString("ActivelyMatchingItems", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Matched a total of {0} sets this round..
- ///
- public static string ActivelyMatchingItemsRound {
- get {
- return ResourceManager.GetString("ActivelyMatchingItemsRound", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to {0} config file will be migrated to the latest syntax....
- ///
- public static string AutomaticFileMigration {
- get {
- return ResourceManager.GetString("AutomaticFileMigration", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ASF will automatically check for new versions every {0}..
- ///
public static string AutoUpdateCheckInfo {
get {
return ResourceManager.GetString("AutoUpdateCheckInfo", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Accepted donation trade: {0}.
- ///
- public static string BotAcceptedDonationTrade {
- get {
- return ResourceManager.GetString("BotAcceptedDonationTrade", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Accepting gift: {0}....
- ///
- public static string BotAcceptingGift {
- get {
- return ResourceManager.GetString("BotAcceptingGift", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Account is no longer occupied: farming process resumed!.
- ///
- public static string BotAccountFree {
- get {
- return ResourceManager.GetString("BotAccountFree", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to This account is limited, farming process is unavailable until the restriction is removed!.
- ///
- public static string BotAccountLimited {
- get {
- return ResourceManager.GetString("BotAccountLimited", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to This account is locked, farming process is permanently unavailable!.
- ///
- public static string BotAccountLocked {
- get {
- return ResourceManager.GetString("BotAccountLocked", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Account is currently being used: ASF will resume farming when it's free....
- ///
- public static string BotAccountOccupied {
- get {
- return ResourceManager.GetString("BotAccountOccupied", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ID: {0} | Status: {1}.
- ///
- public static string BotAddLicense {
- get {
- return ResourceManager.GetString("BotAddLicense", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ID: {0} | Status: {1} | Items: {2}.
- ///
- public static string BotAddLicenseWithItems {
- get {
- return ResourceManager.GetString("BotAddLicenseWithItems", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to This bot is already running!.
- ///
- public static string BotAlreadyRunning {
- get {
- return ResourceManager.GetString("BotAlreadyRunning", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to This bot has already stopped!.
- ///
- public static string BotAlreadyStopped {
- get {
- return ResourceManager.GetString("BotAlreadyStopped", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Converting .maFile into ASF format....
- ///
- public static string BotAuthenticatorConverting {
- get {
- return ResourceManager.GetString("BotAuthenticatorConverting", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Successfully finished importing mobile authenticator!.
- ///
- public static string BotAuthenticatorImportFinished {
- get {
- return ResourceManager.GetString("BotAuthenticatorImportFinished", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to 2FA Token: {0}.
- ///
- public static string BotAuthenticatorToken {
- get {
- return ResourceManager.GetString("BotAuthenticatorToken", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Automatic farming has paused!.
- ///
- public static string BotAutomaticIdlingNowPaused {
- get {
- return ResourceManager.GetString("BotAutomaticIdlingNowPaused", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Automatic farming has resumed!.
- ///
- public static string BotAutomaticIdlingNowResumed {
- get {
- return ResourceManager.GetString("BotAutomaticIdlingNowResumed", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Automatic farming is paused already!.
- ///
- public static string BotAutomaticIdlingPausedAlready {
- get {
- return ResourceManager.GetString("BotAutomaticIdlingPausedAlready", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Automatic farming is resumed already!.
- ///
- public static string BotAutomaticIdlingResumedAlready {
- get {
- return ResourceManager.GetString("BotAutomaticIdlingResumedAlready", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Connected to Steam!.
- ///
- public static string BotConnected {
- get {
- return ResourceManager.GetString("BotConnected", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Connecting....
- ///
- public static string BotConnecting {
- get {
- return ResourceManager.GetString("BotConnecting", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Connection to Steam Network lost. Reconnecting....
- ///
- public static string BotConnectionLost {
- get {
- return ResourceManager.GetString("BotConnectionLost", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Disconnected from Steam!.
- ///
- public static string BotDisconnected {
- get {
- return ResourceManager.GetString("BotDisconnected", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Disconnecting....
- ///
- public static string BotDisconnecting {
- get {
- return ResourceManager.GetString("BotDisconnecting", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Waiting up to {0} to ensure that we're free to start farming....
- ///
- public static string BotExtraIdlingCooldown {
- get {
- return ResourceManager.GetString("BotExtraIdlingCooldown", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot has {0} games remaining in its background queue..
- ///
- public static string BotGamesToRedeemInBackgroundCount {
- get {
- return ResourceManager.GetString("BotGamesToRedeemInBackgroundCount", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Generating Steam parental code, this can take a while, consider putting it in the config instead....
- ///
- public static string BotGeneratingSteamParentalCode {
- get {
- return ResourceManager.GetString("BotGeneratingSteamParentalCode", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Successfully handled {0} confirmations!.
- ///
- public static string BotHandledConfirmations {
- get {
- return ResourceManager.GetString("BotHandledConfirmations", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot has no wallet..
- ///
- public static string BotHasNoWallet {
- get {
- return ResourceManager.GetString("BotHasNoWallet", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Failed to disconnect the client. Abandoning this bot instance!.
- ///
- public static string BotHeartBeatFailed {
- get {
- return ResourceManager.GetString("BotHeartBeatFailed", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Playing selected {0}: {1}.
- ///
- public static string BotIdlingSelectedGames {
- get {
- return ResourceManager.GetString("BotIdlingSelectedGames", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Not starting this bot instance because it's disabled in config file!.
- ///
- public static string BotInstanceNotStartingBecauseDisabled {
- get {
- return ResourceManager.GetString("BotInstanceNotStartingBecauseDisabled", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Received TwoFactorCodeMismatch error code {0} times in a row. Either your 2FA credentials are no longer valid, or your clock is out of sync, aborting!.
- ///
- public static string BotInvalidAuthenticatorDuringLogin {
- get {
- return ResourceManager.GetString("BotInvalidAuthenticatorDuringLogin", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Received InvalidPassword error code {0} times in a row. Your password for this account is most likely wrong, aborting!.
- ///
- public static string BotInvalidPasswordDuringLogin {
- get {
- return ResourceManager.GetString("BotInvalidPasswordDuringLogin", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot has level {0}..
- ///
- public static string BotLevel {
- get {
- return ResourceManager.GetString("BotLevel", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Logged off of Steam: {0}.
- ///
- public static string BotLoggedOff {
- get {
- return ResourceManager.GetString("BotLoggedOff", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Successfully logged on as {0}..
- ///
- public static string BotLoggedOn {
- get {
- return ResourceManager.GetString("BotLoggedOn", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Logging in....
- ///
- public static string BotLoggingIn {
- get {
- return ResourceManager.GetString("BotLoggingIn", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to This account seems to be used in another ASF instance, which is undefined behaviour, refusing to keep it running!.
- ///
- public static string BotLogonSessionReplaced {
- get {
- return ResourceManager.GetString("BotLogonSessionReplaced", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Trade offer failed!.
- ///
- public static string BotLootingFailed {
- get {
- return ResourceManager.GetString("BotLootingFailed", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Trade couldn't be sent because there is no user with master permission defined!.
- ///
- public static string BotLootingMasterNotDefined {
- get {
- return ResourceManager.GetString("BotLootingMasterNotDefined", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Trade offer sent successfully!.
- ///
- public static string BotLootingSuccess {
- get {
- return ResourceManager.GetString("BotLootingSuccess", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to This bot doesn't have ASF 2FA enabled! Did you forget to import your authenticator as ASF 2FA?.
- ///
- public static string BotNoASFAuthenticator {
- get {
- return ResourceManager.GetString("BotNoASFAuthenticator", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to This bot instance is not connected!.
- ///
- public static string BotNotConnected {
- get {
- return ResourceManager.GetString("BotNotConnected", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Couldn't find any bot named {0}!.
- ///
- public static string BotNotFound {
- get {
- return ResourceManager.GetString("BotNotFound", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Not owned yet: {0}.
- ///
- public static string BotNotOwnedYet {
- get {
- return ResourceManager.GetString("BotNotOwnedYet", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Owned already: {0}.
- ///
- public static string BotOwnedAlready {
- get {
- return ResourceManager.GetString("BotOwnedAlready", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Owned already: {0} | {1}.
- ///
- public static string BotOwnedAlreadyWithName {
- get {
- return ResourceManager.GetString("BotOwnedAlreadyWithName", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to {0}/{1} bots already own game {2}..
- ///
- public static string BotOwnsOverviewPerGame {
- get {
- return ResourceManager.GetString("BotOwnsOverviewPerGame", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Points balance: {0}.
- ///
- public static string BotPointsBalance {
- get {
- return ResourceManager.GetString("BotPointsBalance", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Rate limit exceeded, we will retry after {0} of cooldown....
- ///
- public static string BotRateLimitExceeded {
- get {
- return ResourceManager.GetString("BotRateLimitExceeded", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Reconnecting....
- ///
- public static string BotReconnecting {
- get {
- return ResourceManager.GetString("BotReconnecting", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Key: {0} | Status: {1}.
- ///
- public static string BotRedeem {
- get {
- return ResourceManager.GetString("BotRedeem", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Key: {0} | Status: {1} | Items: {2}.
- ///
- public static string BotRedeemWithItems {
- get {
- return ResourceManager.GetString("BotRedeemWithItems", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Refreshing packages data....
- ///
- public static string BotRefreshingPackagesData {
- get {
- return ResourceManager.GetString("BotRefreshingPackagesData", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Removed expired login key!.
- ///
- public static string BotRemovedExpiredLoginKey {
- get {
- return ResourceManager.GetString("BotRemovedExpiredLoginKey", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to You can't send a trade to yourself!.
- ///
- public static string BotSendingTradeToYourself {
- get {
- return ResourceManager.GetString("BotSendingTradeToYourself", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Current memory usage: {0} MB.
- ///Process uptime: {1}.
- ///
- public static string BotStats {
- get {
- return ResourceManager.GetString("BotStats", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot is connecting to Steam network..
- ///
- public static string BotStatusConnecting {
- get {
- return ResourceManager.GetString("BotStatusConnecting", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot is farming game: {0} ({1}, {2} card drops remaining) from a total of {3} games ({4} cards) left to farm (~{5} remaining)..
- ///
- public static string BotStatusIdling {
- get {
- return ResourceManager.GetString("BotStatusIdling", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot is farming games: {0} from a total of {1} games ({2} cards) left to farm (~{3} remaining)..
- ///
- public static string BotStatusIdlingList {
- get {
- return ResourceManager.GetString("BotStatusIdlingList", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot is limited and can't drop any cards through farming..
- ///
- public static string BotStatusLimited {
- get {
- return ResourceManager.GetString("BotStatusLimited", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot is locked and can't drop any cards through farming..
- ///
- public static string BotStatusLocked {
- get {
- return ResourceManager.GetString("BotStatusLocked", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot is not farming anything..
- ///
- public static string BotStatusNotIdling {
- get {
- return ResourceManager.GetString("BotStatusNotIdling", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot is not running..
- ///
- public static string BotStatusNotRunning {
- get {
- return ResourceManager.GetString("BotStatusNotRunning", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to There are {0}/{1} bots running, with total of {2} games ({3} cards) left to farm..
- ///
- public static string BotStatusOverview {
- get {
- return ResourceManager.GetString("BotStatusOverview", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot is paused or running in manual mode..
- ///
- public static string BotStatusPaused {
- get {
- return ResourceManager.GetString("BotStatusPaused", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Bot is currently being used..
- ///
- public static string BotStatusPlayingNotAvailable {
- get {
- return ResourceManager.GetString("BotStatusPlayingNotAvailable", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Could not initialize SteamDirectory: connecting with Steam Network might take much longer than usual!.
- ///
- public static string BotSteamDirectoryInitializationFailed {
- get {
- return ResourceManager.GetString("BotSteamDirectoryInitializationFailed", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Stopping....
- ///
- public static string BotStopping {
- get {
- return ResourceManager.GetString("BotStopping", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to The trade offer {0} is determined to be {1} due to {2}..
- ///
- public static string BotTradeOfferResult {
- get {
- return ResourceManager.GetString("BotTradeOfferResult", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Unable to login to Steam: {0}/{1}.
- ///
- public static string BotUnableToLogin {
- get {
- return ResourceManager.GetString("BotUnableToLogin", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to {0} V{1}.
- ///
- public static string BotVersion {
- get {
- return ResourceManager.GetString("BotVersion", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Wallet balance: {0} {1}.
- ///
- public static string BotWalletBalance {
- get {
- return ResourceManager.GetString("BotWalletBalance", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Checking first badge page....
- ///
- public static string CheckingFirstBadgePage {
- get {
- return ResourceManager.GetString("CheckingFirstBadgePage", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Checking other badge pages....
- ///
- public static string CheckingOtherBadgePages {
- get {
- return ResourceManager.GetString("CheckingOtherBadgePages", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Remote server doesn't know anything about the release we're updating to. This situation is possible if the release was published recently - refusing to proceed with the update procedure right away as an additional security measure..
- ///
- public static string ChecksumMissing {
- get {
- return ResourceManager.GetString("ChecksumMissing", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Remote server has replied with a different checksum, this might indicate corrupted download or MITM attack, refusing to proceed with the update procedure!.
- ///
- public static string ChecksumWrong {
- get {
- return ResourceManager.GetString("ChecksumWrong", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Chosen farming algorithm: {0}.
- ///
- public static string ChosenFarmingAlgorithm {
- get {
- return ResourceManager.GetString("ChosenFarmingAlgorithm", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Clearing Steam discovery queue #{0}....
- ///
- public static string ClearingDiscoveryQueue {
- get {
- return ResourceManager.GetString("ClearingDiscoveryQueue", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Content:
- ///{0}.
- ///
public static string Content {
get {
return ResourceManager.GetString("Content", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Done!.
- ///
- public static string Done {
- get {
- return ResourceManager.GetString("Done", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Done matching Steam items, round #{0}..
- ///
- public static string DoneActivelyMatchingItems {
- get {
- return ResourceManager.GetString("DoneActivelyMatchingItems", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Done clearing Steam discovery queue #{0}..
- ///
- public static string DoneClearingDiscoveryQueue {
- get {
- return ResourceManager.GetString("DoneClearingDiscoveryQueue", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Enter command: .
- ///
- public static string EnterCommand {
- get {
- return ResourceManager.GetString("EnterCommand", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Aborted!.
- ///
- public static string ErrorAborted {
- get {
- return ResourceManager.GetString("ErrorAborted", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Access denied!.
- ///
- public static string ErrorAccessDenied {
- get {
- return ResourceManager.GetString("ErrorAccessDenied", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Your bot config is invalid. Please verify content of {0} and try again!.
- ///
- public static string ErrorBotConfigInvalid {
- get {
- return ResourceManager.GetString("ErrorBotConfigInvalid", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Config directory could not be found, aborting!.
- ///
- public static string ErrorConfigDirectoryNotFound {
- get {
- return ResourceManager.GetString("ErrorConfigDirectoryNotFound", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Configured {0} property is invalid: {1}.
- ///
public static string ErrorConfigPropertyInvalid {
get {
return ResourceManager.GetString("ErrorConfigPropertyInvalid", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Persistent database could not be loaded, if issue persists, please remove {0} in order to recreate the database!.
- ///
- public static string ErrorDatabaseInvalid {
- get {
- return ResourceManager.GetString("ErrorDatabaseInvalid", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ASF V{0} has run into fatal exception before core logging module was even able to initialize!.
- ///
public static string ErrorEarlyFatalExceptionInfo {
get {
return ResourceManager.GetString("ErrorEarlyFatalExceptionInfo", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Exception: {0}() {1}
- ///StackTrace:
- ///{2}.
- ///
public static string ErrorEarlyFatalExceptionPrint {
get {
return ResourceManager.GetString("ErrorEarlyFatalExceptionPrint", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Exiting with nonzero error code!.
- ///
public static string ErrorExitingWithNonZeroErrorCode {
get {
return ResourceManager.GetString("ErrorExitingWithNonZeroErrorCode", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Request failing: {0}.
- ///
public static string ErrorFailingRequest {
get {
return ResourceManager.GetString("ErrorFailingRequest", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to This function is available only in headless mode!.
- ///
- public static string ErrorFunctionOnlyInHeadlessMode {
- get {
- return ResourceManager.GetString("ErrorFunctionOnlyInHeadlessMode", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Global config could not be loaded. Make sure that {0} exists and is valid! Follow 'setting up' guide on the wiki if you're confused..
- ///
public static string ErrorGlobalConfigNotLoaded {
get {
return ResourceManager.GetString("ErrorGlobalConfigNotLoaded", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Global config file has been removed!.
- ///
- public static string ErrorGlobalConfigRemoved {
- get {
- return ResourceManager.GetString("ErrorGlobalConfigRemoved", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Your provided CurrentCulture is invalid, ASF will keep running with the default one!.
- ///
- public static string ErrorInvalidCurrentCulture {
- get {
- return ResourceManager.GetString("ErrorInvalidCurrentCulture", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to The IP address {0} is not banned!.
- ///
- public static string ErrorIPNotBanned {
- get {
- return ResourceManager.GetString("ErrorIPNotBanned", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to {0} is empty!.
- ///
- public static string ErrorIsEmpty {
- get {
- return ResourceManager.GetString("ErrorIsEmpty", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to {0} is invalid!.
- ///
public static string ErrorIsInvalid {
get {
return ResourceManager.GetString("ErrorIsInvalid", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to No bots are defined. Did you forget to configure your ASF? Follow 'setting up' guide on the wiki if you're confused..
- ///
public static string ErrorNoBotsDefined {
get {
return ResourceManager.GetString("ErrorNoBotsDefined", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to {0} is null!.
- ///
public static string ErrorObjectIsNull {
get {
return ResourceManager.GetString("ErrorObjectIsNull", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Parsing {0} failed!.
- ///
public static string ErrorParsingObject {
get {
return ResourceManager.GetString("ErrorParsingObject", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Request failed after {0} attempts!.
- ///
public static string ErrorRequestFailedTooManyTimes {
get {
return ResourceManager.GetString("ErrorRequestFailedTooManyTimes", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to ASF process is already running for this working directory, aborting!.
- ///
- public static string ErrorSingleInstanceRequired {
- get {
- return ResourceManager.GetString("ErrorSingleInstanceRequired", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Could not check latest version!.
- ///
public static string ErrorUpdateCheckFailed {
get {
return ResourceManager.GetString("ErrorUpdateCheckFailed", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Could not proceed with update because there is no asset that relates to currently running version! Automatic update to that version is not possible..
- ///
public static string ErrorUpdateNoAssetForThisVersion {
get {
return ResourceManager.GetString("ErrorUpdateNoAssetForThisVersion", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Could not proceed with an update because that version doesn't include any assets!.
- ///
public static string ErrorUpdateNoAssets {
get {
return ResourceManager.GetString("ErrorUpdateNoAssets", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Received a request for user input, but process is running in headless mode!.
- ///
public static string ErrorUserInputRunningInHeadlessMode {
get {
return ResourceManager.GetString("ErrorUserInputRunningInHeadlessMode", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Executing....
- ///
- public static string Executing {
- get {
- return ResourceManager.GetString("Executing", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Exiting....
- ///
public static string Exiting {
get {
return ResourceManager.GetString("Exiting", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Fetching checksum from the remote server....
- ///
- public static string FetchingChecksumFromRemoteServer {
- get {
- return ResourceManager.GetString("FetchingChecksumFromRemoteServer", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to We have a total of {0} games ({1} cards) left to farm (~{2} remaining)....
- ///
- public static string GamesToIdle {
- get {
- return ResourceManager.GetString("GamesToIdle", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Global config file has been changed!.
- ///
- public static string GlobalConfigChanged {
- get {
- return ResourceManager.GetString("GlobalConfigChanged", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Farming finished!.
- ///
- public static string IdlingFinished {
- get {
- return ResourceManager.GetString("IdlingFinished", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Finished farming: {0} ({1}) after {2} of playtime!.
- ///
- public static string IdlingFinishedForGame {
- get {
- return ResourceManager.GetString("IdlingFinishedForGame", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Finished farming games: {0}.
- ///
- public static string IdlingFinishedForGames {
- get {
- return ResourceManager.GetString("IdlingFinishedForGames", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Farming {0} ({1}) is temporarily disabled, as ASF is not able to play that game at the moment..
- ///
- public static string IdlingGameNotPossible {
- get {
- return ResourceManager.GetString("IdlingGameNotPossible", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Farming status for {0} ({1}): {2} cards remaining.
- ///
- public static string IdlingStatusForGame {
- get {
- return ResourceManager.GetString("IdlingStatusForGame", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Farming stopped!.
- ///
- public static string IdlingStopped {
- get {
- return ResourceManager.GetString("IdlingStopped", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Ignoring this request, as permanent pause is enabled!.
- ///
- public static string IgnoredPermanentPauseEnabled {
- get {
- return ResourceManager.GetString("IgnoredPermanentPauseEnabled", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Ignoring trade: {0}.
- ///
- public static string IgnoringTrade {
- get {
- return ResourceManager.GetString("IgnoringTrade", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Initializing {0}....
- ///
- public static string Initializing {
- get {
- return ResourceManager.GetString("Initializing", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Interactive console is now active, type 'c' in order to enter command mode..
- ///
- public static string InteractiveConsoleEnabled {
- get {
- return ResourceManager.GetString("InteractiveConsoleEnabled", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to IPC config has been changed!.
- ///
- public static string IPCConfigChanged {
- get {
- return ResourceManager.GetString("IPCConfigChanged", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to IPC server ready!.
- ///
- public static string IPCReady {
- get {
- return ResourceManager.GetString("IPCReady", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Starting IPC server....
- ///
- public static string IPCStarting {
- get {
- return ResourceManager.GetString("IPCStarting", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Logging in to {0}....
- ///
- public static string LoggingIn {
- get {
- return ResourceManager.GetString("LoggingIn", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to No bots are running, exiting....
- ///
- public static string NoBotsAreRunning {
- get {
- return ResourceManager.GetString("NoBotsAreRunning", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Nothing found!.
- ///
- public static string NothingFound {
- get {
- return ResourceManager.GetString("NothingFound", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to We don't have anything to farm on this account!.
- ///
- public static string NothingToIdle {
- get {
- return ResourceManager.GetString("NothingToIdle", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Now farming: {0} ({1}).
- ///
- public static string NowIdling {
- get {
- return ResourceManager.GetString("NowIdling", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Now farming: {0}.
- ///
- public static string NowIdlingList {
- get {
- return ResourceManager.GetString("NowIdlingList", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Patching ASF files....
- ///
- public static string PatchingFiles {
- get {
- return ResourceManager.GetString("PatchingFiles", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Playing is currently unavailable, we'll try again later!.
- ///
- public static string PlayingNotAvailable {
- get {
- return ResourceManager.GetString("PlayingNotAvailable", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Please wait....
- ///
- public static string PleaseWait {
- get {
- return ResourceManager.GetString("PleaseWait", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to {0} has been loaded successfully!.
- ///
- public static string PluginLoaded {
- get {
- return ResourceManager.GetString("PluginLoaded", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Loading {0} V{1}....
- ///
- public static string PluginLoading {
- get {
- return ResourceManager.GetString("PluginLoading", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to You've loaded one or multiple custom plugins into ASF. Since we're unable to offer support for modded setups, please contact the appropriate developers of the plugins that you decided to use in case of any issues..
- ///
- public static string PluginsWarning {
- get {
- return ResourceManager.GetString("PluginsWarning", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Refreshing our session!.
- ///
- public static string RefreshingOurSession {
- get {
- return ResourceManager.GetString("RefreshingOurSession", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Rejecting trade: {0}.
- ///
- public static string RejectingTrade {
- get {
- return ResourceManager.GetString("RejectingTrade", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Restarting....
- ///
- public static string Restarting {
- get {
- return ResourceManager.GetString("Restarting", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Result: {0}.
- ///
- public static string Result {
- get {
- return ResourceManager.GetString("Result", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Starting....
- ///
- public static string Starting {
- get {
- return ResourceManager.GetString("Starting", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Still farming: {0} ({1}).
- ///
- public static string StillIdling {
- get {
- return ResourceManager.GetString("StillIdling", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Still farming: {0}.
- ///
- public static string StillIdlingList {
- get {
- return ResourceManager.GetString("StillIdlingList", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Stopped farming: {0} ({1}).
- ///
- public static string StoppedIdling {
- get {
- return ResourceManager.GetString("StoppedIdling", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Stopped farming: {0}.
- ///
- public static string StoppedIdlingList {
- get {
- return ResourceManager.GetString("StoppedIdlingList", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Success!.
- ///
- public static string Success {
- get {
- return ResourceManager.GetString("Success", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Target bot instance is not connected!.
- ///
- public static string TargetBotNotConnected {
- get {
- return ResourceManager.GetString("TargetBotNotConnected", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to ASF will attempt to use your preferred {0} culture, but translation into that language is only {1} complete. Perhaps you could help us improve the ASF translation for your language?.
- ///
- public static string TranslationIncomplete {
- get {
- return ResourceManager.GetString("TranslationIncomplete", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Unknown command!.
- ///
- public static string UnknownCommand {
- get {
- return ResourceManager.GetString("UnknownCommand", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Unlocking parental account....
- ///
- public static string UnlockingParentalAccount {
- get {
- return ResourceManager.GetString("UnlockingParentalAccount", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Unused keys: {0}.
- ///
- public static string UnusedKeys {
- get {
- return ResourceManager.GetString("UnusedKeys", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Checking for new version....
- ///
- public static string UpdateCheckingNewVersion {
- get {
- return ResourceManager.GetString("UpdateCheckingNewVersion", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Cleaning up old files after update....
- ///
- public static string UpdateCleanup {
- get {
- return ResourceManager.GetString("UpdateCleanup", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Downloading new version: {0} ({1} MB)... While waiting, consider donating if you appreciate the work being done! :).
- ///
- public static string UpdateDownloadingNewVersion {
- get {
- return ResourceManager.GetString("UpdateDownloadingNewVersion", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Update process finished!.
- ///
- public static string UpdateFinished {
- get {
- return ResourceManager.GetString("UpdateFinished", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to New ASF version is available! Consider updating yourself!.
- ///
- public static string UpdateNewVersionAvailable {
- get {
- return ResourceManager.GetString("UpdateNewVersionAvailable", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Local version: {0} | Remote version: {1}.
- ///
- public static string UpdateVersionInfo {
- get {
- return ResourceManager.GetString("UpdateVersionInfo", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Please enter your cryptkey: .
- ///
- public static string UserInputCryptkey {
- get {
- return ResourceManager.GetString("UserInputCryptkey", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Please enter your 2FA code from your Steam authenticator app: .
- ///
- public static string UserInputSteam2FA {
- get {
- return ResourceManager.GetString("UserInputSteam2FA", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Please enter SteamGuard auth code that was sent to your e-mail: .
- ///
- public static string UserInputSteamGuard {
- get {
- return ResourceManager.GetString("UserInputSteamGuard", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Please enter your Steam login: .
- ///
- public static string UserInputSteamLogin {
- get {
- return ResourceManager.GetString("UserInputSteamLogin", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Please enter Steam parental code: .
- ///
- public static string UserInputSteamParentalCode {
- get {
- return ResourceManager.GetString("UserInputSteamParentalCode", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Please enter your Steam password: .
- ///
- public static string UserInputSteamPassword {
- get {
- return ResourceManager.GetString("UserInputSteamPassword", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Verifying checksum of the downloaded binary against the one from the remote server....
- ///
- public static string VerifyingChecksumWithRemoteServer {
- get {
- return ResourceManager.GetString("VerifyingChecksumWithRemoteServer", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Could not get badges' information, we will try again later!.
- ///
- public static string WarningCouldNotCheckBadges {
- get {
- return ResourceManager.GetString("WarningCouldNotCheckBadges", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Could not check cards status for: {0} ({1}), we will try again later!.
- ///
- public static string WarningCouldNotCheckCardsStatus {
- get {
- return ResourceManager.GetString("WarningCouldNotCheckCardsStatus", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to You're using {0} setting of {1} property, but you didn't provide a custom --cryptkey. This entirely defeats the protection, as ASF is forced to use its own (known) key. You should provide a custom --cryptkey for making use of the security benefit offered by this setting..
- ///
- public static string WarningDefaultCryptKeyUsedForEncryption {
- get {
- return ResourceManager.GetString("WarningDefaultCryptKeyUsedForEncryption", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to You're using {0} setting of {1} property, but you didn't provide a custom --cryptkey. You should provide a custom --cryptkey for increased security..
- ///
- public static string WarningDefaultCryptKeyUsedForHashing {
- get {
- return ResourceManager.GetString("WarningDefaultCryptKeyUsedForHashing", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Usage of {0} is deprecated and will be removed in future versions of the program. Please use {1} instead..
- ///
- public static string WarningDeprecated {
- get {
- return ResourceManager.GetString("WarningDeprecated", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to You're running more personal bot accounts than our upper recommended limit ({0}). Be advised that this setup is not supported and might cause various Steam-related issues, including account suspensions. Check out the FAQ for more details..
- ///
- public static string WarningExcessiveBotsCount {
- get {
- return ResourceManager.GetString("WarningExcessiveBotsCount", resourceCulture);
- }
- }
-
- ///
- /// Looks up a localized string similar to Failed!.
- ///
public static string WarningFailed {
get {
return ResourceManager.GetString("WarningFailed", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Failed due to error: {0}.
- ///
- public static string WarningFailedWithError {
+ public static string GlobalConfigChanged {
get {
- return ResourceManager.GetString("WarningFailedWithError", resourceCulture);
+ return ResourceManager.GetString("GlobalConfigChanged", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to ASF detected ID mismatch for {0} ({1}) and will use ID of {2} instead..
- ///
- public static string WarningIdlingGameMismatch {
+ public static string ErrorGlobalConfigRemoved {
get {
- return ResourceManager.GetString("WarningIdlingGameMismatch", resourceCulture);
+ return ResourceManager.GetString("ErrorGlobalConfigRemoved", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to You're using a version that is newer than the latest released version for your update channel. Please note that pre-release versions are meant for users who know how to report bugs, deal with issues and give feedback - no technical support will be given..
- ///
- public static string WarningPreReleaseVersion {
+ public static string IgnoringTrade {
get {
- return ResourceManager.GetString("WarningPreReleaseVersion", resourceCulture);
+ return ResourceManager.GetString("IgnoringTrade", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Please review our privacy policy section on the wiki if you're concerned about what ASF is in fact doing!.
- ///
- public static string WarningPrivacyPolicy {
+ public static string LoggingIn {
get {
- return ResourceManager.GetString("WarningPrivacyPolicy", resourceCulture);
+ return ResourceManager.GetString("LoggingIn", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to You're attempting to run ASF as the administrator (root). This causes a significant security risk to your machine, and as ASF does not require root access for its operation, we recommend to run it as non-administrator user if possible..
- ///
- public static string WarningRunningAsRoot {
+ public static string NoBotsAreRunning {
get {
- return ResourceManager.GetString("WarningRunningAsRoot", resourceCulture);
+ return ResourceManager.GetString("NoBotsAreRunning", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to You're running ASF in unsupported environment, supplying --ignore-unsupported-environment argument. Please note that we do not offer any kind of support for this scenario and you're doing it entirely at your own risk. You've been warned..
- ///
- public static string WarningRunningInUnsupportedEnvironment {
+ public static string RefreshingOurSession {
get {
- return ResourceManager.GetString("WarningRunningInUnsupportedEnvironment", resourceCulture);
+ return ResourceManager.GetString("RefreshingOurSession", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Your encryption key is too short. We recommend to use one that is at least {0} bytes (characters) long..
- ///
- public static string WarningTooShortCryptKey {
+ public static string RejectingTrade {
get {
- return ResourceManager.GetString("WarningTooShortCryptKey", resourceCulture);
+ return ResourceManager.GetString("RejectingTrade", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Unknown command-line argument: {0}.
- ///
- public static string WarningUnknownCommandLineArgument {
+ public static string Restarting {
get {
- return ResourceManager.GetString("WarningUnknownCommandLineArgument", resourceCulture);
+ return ResourceManager.GetString("Restarting", resourceCulture);
+ }
+ }
+
+ public static string Starting {
+ get {
+ return ResourceManager.GetString("Starting", resourceCulture);
+ }
+ }
+
+ public static string Success {
+ get {
+ return ResourceManager.GetString("Success", resourceCulture);
+ }
+ }
+
+ public static string UnlockingParentalAccount {
+ get {
+ return ResourceManager.GetString("UnlockingParentalAccount", resourceCulture);
+ }
+ }
+
+ public static string UpdateCheckingNewVersion {
+ get {
+ return ResourceManager.GetString("UpdateCheckingNewVersion", resourceCulture);
+ }
+ }
+
+ public static string UpdateDownloadingNewVersion {
+ get {
+ return ResourceManager.GetString("UpdateDownloadingNewVersion", resourceCulture);
+ }
+ }
+
+ public static string UpdateFinished {
+ get {
+ return ResourceManager.GetString("UpdateFinished", resourceCulture);
+ }
+ }
+
+ public static string UpdateNewVersionAvailable {
+ get {
+ return ResourceManager.GetString("UpdateNewVersionAvailable", resourceCulture);
+ }
+ }
+
+ public static string UpdateVersionInfo {
+ get {
+ return ResourceManager.GetString("UpdateVersionInfo", resourceCulture);
+ }
+ }
+
+ public static string UserInputSteam2FA {
+ get {
+ return ResourceManager.GetString("UserInputSteam2FA", resourceCulture);
+ }
+ }
+
+ public static string UserInputSteamGuard {
+ get {
+ return ResourceManager.GetString("UserInputSteamGuard", resourceCulture);
+ }
+ }
+
+ public static string UserInputSteamLogin {
+ get {
+ return ResourceManager.GetString("UserInputSteamLogin", resourceCulture);
+ }
+ }
+
+ public static string UserInputSteamParentalCode {
+ get {
+ return ResourceManager.GetString("UserInputSteamParentalCode", resourceCulture);
+ }
+ }
+
+ public static string UserInputSteamPassword {
+ get {
+ return ResourceManager.GetString("UserInputSteamPassword", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Received unknown value for {0}, please report this: {1}.
- ///
public static string WarningUnknownValuePleaseReport {
get {
return ResourceManager.GetString("WarningUnknownValuePleaseReport", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to You're attempting to run {0} variant of ASF in an unsupported environment: {1}. Supply --ignore-unsupported-environment argument if you really know what you're doing..
- ///
- public static string WarningUnsupportedEnvironment {
+ public static string IPCReady {
get {
- return ResourceManager.GetString("WarningUnsupportedEnvironment", resourceCulture);
+ return ResourceManager.GetString("IPCReady", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Your encryption key seems to be weak. Consider choosing a stronger one for increased security. Details: {0}.
- ///
- public static string WarningWeakCryptKey {
+ public static string IPCStarting {
get {
- return ResourceManager.GetString("WarningWeakCryptKey", resourceCulture);
+ return ResourceManager.GetString("IPCStarting", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Your IPC password seems to be weak. Consider choosing a stronger one for increased security. Details: {0}.
- ///
- public static string WarningWeakIPCPassword {
+ public static string BotAlreadyStopped {
get {
- return ResourceManager.GetString("WarningWeakIPCPassword", resourceCulture);
+ return ResourceManager.GetString("BotAlreadyStopped", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Your Steam password for '{0}' seems to be weak. Consider choosing a stronger one for increased security. Details: {1}.
- ///
- public static string WarningWeakSteamPassword {
+ public static string BotNotFound {
get {
- return ResourceManager.GetString("WarningWeakSteamPassword", resourceCulture);
+ return ResourceManager.GetString("BotNotFound", resourceCulture);
+ }
+ }
+
+ public static string BotStatusOverview {
+ get {
+ return ResourceManager.GetString("BotStatusOverview", resourceCulture);
+ }
+ }
+
+ public static string BotStatusIdling {
+ get {
+ return ResourceManager.GetString("BotStatusIdling", resourceCulture);
+ }
+ }
+
+ public static string BotStatusIdlingList {
+ get {
+ return ResourceManager.GetString("BotStatusIdlingList", resourceCulture);
+ }
+ }
+
+ public static string CheckingFirstBadgePage {
+ get {
+ return ResourceManager.GetString("CheckingFirstBadgePage", resourceCulture);
+ }
+ }
+
+ public static string CheckingOtherBadgePages {
+ get {
+ return ResourceManager.GetString("CheckingOtherBadgePages", resourceCulture);
+ }
+ }
+
+ public static string ChosenFarmingAlgorithm {
+ get {
+ return ResourceManager.GetString("ChosenFarmingAlgorithm", resourceCulture);
+ }
+ }
+
+ public static string Done {
+ get {
+ return ResourceManager.GetString("Done", resourceCulture);
+ }
+ }
+
+ public static string GamesToIdle {
+ get {
+ return ResourceManager.GetString("GamesToIdle", resourceCulture);
+ }
+ }
+
+ public static string IdlingFinished {
+ get {
+ return ResourceManager.GetString("IdlingFinished", resourceCulture);
+ }
+ }
+
+ public static string IdlingFinishedForGame {
+ get {
+ return ResourceManager.GetString("IdlingFinishedForGame", resourceCulture);
+ }
+ }
+
+ public static string IdlingFinishedForGames {
+ get {
+ return ResourceManager.GetString("IdlingFinishedForGames", resourceCulture);
+ }
+ }
+
+ public static string IdlingStatusForGame {
+ get {
+ return ResourceManager.GetString("IdlingStatusForGame", resourceCulture);
+ }
+ }
+
+ public static string IdlingStopped {
+ get {
+ return ResourceManager.GetString("IdlingStopped", resourceCulture);
+ }
+ }
+
+ public static string IgnoredPermanentPauseEnabled {
+ get {
+ return ResourceManager.GetString("IgnoredPermanentPauseEnabled", resourceCulture);
+ }
+ }
+
+ public static string NothingToIdle {
+ get {
+ return ResourceManager.GetString("NothingToIdle", resourceCulture);
+ }
+ }
+
+ public static string NowIdling {
+ get {
+ return ResourceManager.GetString("NowIdling", resourceCulture);
+ }
+ }
+
+ public static string NowIdlingList {
+ get {
+ return ResourceManager.GetString("NowIdlingList", resourceCulture);
+ }
+ }
+
+ public static string PlayingNotAvailable {
+ get {
+ return ResourceManager.GetString("PlayingNotAvailable", resourceCulture);
+ }
+ }
+
+ public static string StillIdling {
+ get {
+ return ResourceManager.GetString("StillIdling", resourceCulture);
+ }
+ }
+
+ public static string StillIdlingList {
+ get {
+ return ResourceManager.GetString("StillIdlingList", resourceCulture);
+ }
+ }
+
+ public static string StoppedIdling {
+ get {
+ return ResourceManager.GetString("StoppedIdling", resourceCulture);
+ }
+ }
+
+ public static string StoppedIdlingList {
+ get {
+ return ResourceManager.GetString("StoppedIdlingList", resourceCulture);
+ }
+ }
+
+ public static string UnknownCommand {
+ get {
+ return ResourceManager.GetString("UnknownCommand", resourceCulture);
+ }
+ }
+
+ public static string WarningCouldNotCheckBadges {
+ get {
+ return ResourceManager.GetString("WarningCouldNotCheckBadges", resourceCulture);
+ }
+ }
+
+ public static string WarningCouldNotCheckCardsStatus {
+ get {
+ return ResourceManager.GetString("WarningCouldNotCheckCardsStatus", resourceCulture);
+ }
+ }
+
+ public static string BotAcceptingGift {
+ get {
+ return ResourceManager.GetString("BotAcceptingGift", resourceCulture);
+ }
+ }
+
+ public static string BotAccountLimited {
+ get {
+ return ResourceManager.GetString("BotAccountLimited", resourceCulture);
+ }
+ }
+
+ public static string BotAddLicense {
+ get {
+ return ResourceManager.GetString("BotAddLicense", resourceCulture);
+ }
+ }
+
+ public static string BotAddLicenseWithItems {
+ get {
+ return ResourceManager.GetString("BotAddLicenseWithItems", resourceCulture);
+ }
+ }
+
+ public static string BotAlreadyRunning {
+ get {
+ return ResourceManager.GetString("BotAlreadyRunning", resourceCulture);
+ }
+ }
+
+ public static string BotAuthenticatorConverting {
+ get {
+ return ResourceManager.GetString("BotAuthenticatorConverting", resourceCulture);
+ }
+ }
+
+ public static string BotAuthenticatorImportFinished {
+ get {
+ return ResourceManager.GetString("BotAuthenticatorImportFinished", resourceCulture);
+ }
+ }
+
+ public static string BotAuthenticatorToken {
+ get {
+ return ResourceManager.GetString("BotAuthenticatorToken", resourceCulture);
+ }
+ }
+
+ public static string BotAutomaticIdlingNowPaused {
+ get {
+ return ResourceManager.GetString("BotAutomaticIdlingNowPaused", resourceCulture);
+ }
+ }
+
+ public static string BotAutomaticIdlingNowResumed {
+ get {
+ return ResourceManager.GetString("BotAutomaticIdlingNowResumed", resourceCulture);
+ }
+ }
+
+ public static string BotAutomaticIdlingPausedAlready {
+ get {
+ return ResourceManager.GetString("BotAutomaticIdlingPausedAlready", resourceCulture);
+ }
+ }
+
+ public static string BotAutomaticIdlingResumedAlready {
+ get {
+ return ResourceManager.GetString("BotAutomaticIdlingResumedAlready", resourceCulture);
+ }
+ }
+
+ public static string BotConnected {
+ get {
+ return ResourceManager.GetString("BotConnected", resourceCulture);
+ }
+ }
+
+ public static string BotDisconnected {
+ get {
+ return ResourceManager.GetString("BotDisconnected", resourceCulture);
+ }
+ }
+
+ public static string BotDisconnecting {
+ get {
+ return ResourceManager.GetString("BotDisconnecting", resourceCulture);
+ }
+ }
+
+ public static string BotInstanceNotStartingBecauseDisabled {
+ get {
+ return ResourceManager.GetString("BotInstanceNotStartingBecauseDisabled", resourceCulture);
+ }
+ }
+
+ public static string BotInvalidAuthenticatorDuringLogin {
+ get {
+ return ResourceManager.GetString("BotInvalidAuthenticatorDuringLogin", resourceCulture);
+ }
+ }
+
+ public static string BotLoggedOff {
+ get {
+ return ResourceManager.GetString("BotLoggedOff", resourceCulture);
+ }
+ }
+
+ public static string BotLoggedOn {
+ get {
+ return ResourceManager.GetString("BotLoggedOn", resourceCulture);
+ }
+ }
+
+ public static string BotLoggingIn {
+ get {
+ return ResourceManager.GetString("BotLoggingIn", resourceCulture);
+ }
+ }
+
+ public static string BotLogonSessionReplaced {
+ get {
+ return ResourceManager.GetString("BotLogonSessionReplaced", resourceCulture);
+ }
+ }
+
+ public static string BotLootingFailed {
+ get {
+ return ResourceManager.GetString("BotLootingFailed", resourceCulture);
+ }
+ }
+
+ public static string BotLootingMasterNotDefined {
+ get {
+ return ResourceManager.GetString("BotLootingMasterNotDefined", resourceCulture);
+ }
+ }
+
+ public static string BotLootingSuccess {
+ get {
+ return ResourceManager.GetString("BotLootingSuccess", resourceCulture);
+ }
+ }
+
+ public static string BotSendingTradeToYourself {
+ get {
+ return ResourceManager.GetString("BotSendingTradeToYourself", resourceCulture);
+ }
+ }
+
+ public static string BotNoASFAuthenticator {
+ get {
+ return ResourceManager.GetString("BotNoASFAuthenticator", resourceCulture);
+ }
+ }
+
+ public static string BotNotConnected {
+ get {
+ return ResourceManager.GetString("BotNotConnected", resourceCulture);
+ }
+ }
+
+ public static string BotNotOwnedYet {
+ get {
+ return ResourceManager.GetString("BotNotOwnedYet", resourceCulture);
+ }
+ }
+
+ public static string BotOwnedAlreadyWithName {
+ get {
+ return ResourceManager.GetString("BotOwnedAlreadyWithName", resourceCulture);
+ }
+ }
+
+ public static string BotPointsBalance {
+ get {
+ return ResourceManager.GetString("BotPointsBalance", resourceCulture);
+ }
+ }
+
+ public static string BotRateLimitExceeded {
+ get {
+ return ResourceManager.GetString("BotRateLimitExceeded", resourceCulture);
+ }
+ }
+
+ public static string BotReconnecting {
+ get {
+ return ResourceManager.GetString("BotReconnecting", resourceCulture);
+ }
+ }
+
+ public static string BotRedeem {
+ get {
+ return ResourceManager.GetString("BotRedeem", resourceCulture);
+ }
+ }
+
+ public static string BotRedeemWithItems {
+ get {
+ return ResourceManager.GetString("BotRedeemWithItems", resourceCulture);
+ }
+ }
+
+ public static string BotRemovedExpiredLoginKey {
+ get {
+ return ResourceManager.GetString("BotRemovedExpiredLoginKey", resourceCulture);
+ }
+ }
+
+ public static string BotStatusNotIdling {
+ get {
+ return ResourceManager.GetString("BotStatusNotIdling", resourceCulture);
+ }
+ }
+
+ public static string BotStatusLimited {
+ get {
+ return ResourceManager.GetString("BotStatusLimited", resourceCulture);
+ }
+ }
+
+ public static string BotStatusConnecting {
+ get {
+ return ResourceManager.GetString("BotStatusConnecting", resourceCulture);
+ }
+ }
+
+ public static string BotStatusNotRunning {
+ get {
+ return ResourceManager.GetString("BotStatusNotRunning", resourceCulture);
+ }
+ }
+
+ public static string BotStatusPaused {
+ get {
+ return ResourceManager.GetString("BotStatusPaused", resourceCulture);
+ }
+ }
+
+ public static string BotStatusPlayingNotAvailable {
+ get {
+ return ResourceManager.GetString("BotStatusPlayingNotAvailable", resourceCulture);
+ }
+ }
+
+ public static string BotUnableToLogin {
+ get {
+ return ResourceManager.GetString("BotUnableToLogin", resourceCulture);
+ }
+ }
+
+ public static string ErrorIsEmpty {
+ get {
+ return ResourceManager.GetString("ErrorIsEmpty", resourceCulture);
+ }
+ }
+
+ public static string UnusedKeys {
+ get {
+ return ResourceManager.GetString("UnusedKeys", resourceCulture);
+ }
+ }
+
+ public static string WarningFailedWithError {
+ get {
+ return ResourceManager.GetString("WarningFailedWithError", resourceCulture);
+ }
+ }
+
+ public static string BotConnectionLost {
+ get {
+ return ResourceManager.GetString("BotConnectionLost", resourceCulture);
+ }
+ }
+
+ public static string BotAccountFree {
+ get {
+ return ResourceManager.GetString("BotAccountFree", resourceCulture);
+ }
+ }
+
+ public static string BotAccountOccupied {
+ get {
+ return ResourceManager.GetString("BotAccountOccupied", resourceCulture);
+ }
+ }
+
+ public static string BotConnecting {
+ get {
+ return ResourceManager.GetString("BotConnecting", resourceCulture);
+ }
+ }
+
+ public static string BotHeartBeatFailed {
+ get {
+ return ResourceManager.GetString("BotHeartBeatFailed", resourceCulture);
+ }
+ }
+
+ public static string BotSteamDirectoryInitializationFailed {
+ get {
+ return ResourceManager.GetString("BotSteamDirectoryInitializationFailed", resourceCulture);
+ }
+ }
+
+ public static string BotStopping {
+ get {
+ return ResourceManager.GetString("BotStopping", resourceCulture);
+ }
+ }
+
+ public static string ErrorBotConfigInvalid {
+ get {
+ return ResourceManager.GetString("ErrorBotConfigInvalid", resourceCulture);
+ }
+ }
+
+ public static string ErrorDatabaseInvalid {
+ get {
+ return ResourceManager.GetString("ErrorDatabaseInvalid", resourceCulture);
+ }
+ }
+
+ public static string Initializing {
+ get {
+ return ResourceManager.GetString("Initializing", resourceCulture);
+ }
+ }
+
+ public static string WarningPrivacyPolicy {
+ get {
+ return ResourceManager.GetString("WarningPrivacyPolicy", resourceCulture);
+ }
+ }
+
+ public static string Welcome {
+ get {
+ return ResourceManager.GetString("Welcome", resourceCulture);
+ }
+ }
+
+ public static string ErrorInvalidCurrentCulture {
+ get {
+ return ResourceManager.GetString("ErrorInvalidCurrentCulture", resourceCulture);
+ }
+ }
+
+ public static string TranslationIncomplete {
+ get {
+ return ResourceManager.GetString("TranslationIncomplete", resourceCulture);
+ }
+ }
+
+ public static string IdlingGameNotPossible {
+ get {
+ return ResourceManager.GetString("IdlingGameNotPossible", resourceCulture);
+ }
+ }
+
+ public static string WarningIdlingGameMismatch {
+ get {
+ return ResourceManager.GetString("WarningIdlingGameMismatch", resourceCulture);
+ }
+ }
+
+ public static string BotVersion {
+ get {
+ return ResourceManager.GetString("BotVersion", resourceCulture);
+ }
+ }
+
+ public static string BotAccountLocked {
+ get {
+ return ResourceManager.GetString("BotAccountLocked", resourceCulture);
+ }
+ }
+
+ public static string BotStatusLocked {
+ get {
+ return ResourceManager.GetString("BotStatusLocked", resourceCulture);
+ }
+ }
+
+ public static string ErrorFunctionOnlyInHeadlessMode {
+ get {
+ return ResourceManager.GetString("ErrorFunctionOnlyInHeadlessMode", resourceCulture);
+ }
+ }
+
+ public static string BotOwnedAlready {
+ get {
+ return ResourceManager.GetString("BotOwnedAlready", resourceCulture);
+ }
+ }
+
+ public static string ErrorAccessDenied {
+ get {
+ return ResourceManager.GetString("ErrorAccessDenied", resourceCulture);
+ }
+ }
+
+ public static string WarningPreReleaseVersion {
+ get {
+ return ResourceManager.GetString("WarningPreReleaseVersion", resourceCulture);
+ }
+ }
+
+ public static string BotStats {
+ get {
+ return ResourceManager.GetString("BotStats", resourceCulture);
+ }
+ }
+
+ public static string ClearingDiscoveryQueue {
+ get {
+ return ResourceManager.GetString("ClearingDiscoveryQueue", resourceCulture);
+ }
+ }
+
+ public static string DoneClearingDiscoveryQueue {
+ get {
+ return ResourceManager.GetString("DoneClearingDiscoveryQueue", resourceCulture);
+ }
+ }
+
+ public static string BotOwnsOverviewPerGame {
+ get {
+ return ResourceManager.GetString("BotOwnsOverviewPerGame", resourceCulture);
+ }
+ }
+
+ public static string BotRefreshingPackagesData {
+ get {
+ return ResourceManager.GetString("BotRefreshingPackagesData", resourceCulture);
+ }
+ }
+
+ public static string WarningDeprecated {
+ get {
+ return ResourceManager.GetString("WarningDeprecated", resourceCulture);
+ }
+ }
+
+ public static string BotAcceptedDonationTrade {
+ get {
+ return ResourceManager.GetString("BotAcceptedDonationTrade", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to Workaround for {0} bug has been triggered..
- ///
public static string WarningWorkaroundTriggered {
get {
return ResourceManager.GetString("WarningWorkaroundTriggered", resourceCulture);
}
}
- ///
- /// Looks up a localized string similar to It looks like it's your first launch of the program, welcome!.
- ///
- public static string Welcome {
+ public static string TargetBotNotConnected {
get {
- return ResourceManager.GetString("Welcome", resourceCulture);
+ return ResourceManager.GetString("TargetBotNotConnected", resourceCulture);
+ }
+ }
+
+ public static string BotWalletBalance {
+ get {
+ return ResourceManager.GetString("BotWalletBalance", resourceCulture);
+ }
+ }
+
+ public static string BotHasNoWallet {
+ get {
+ return ResourceManager.GetString("BotHasNoWallet", resourceCulture);
+ }
+ }
+
+ public static string BotLevel {
+ get {
+ return ResourceManager.GetString("BotLevel", resourceCulture);
+ }
+ }
+
+ public static string ActivelyMatchingItems {
+ get {
+ return ResourceManager.GetString("ActivelyMatchingItems", resourceCulture);
+ }
+ }
+
+ public static string DoneActivelyMatchingItems {
+ get {
+ return ResourceManager.GetString("DoneActivelyMatchingItems", resourceCulture);
+ }
+ }
+
+ public static string ErrorAborted {
+ get {
+ return ResourceManager.GetString("ErrorAborted", resourceCulture);
+ }
+ }
+
+ public static string WarningExcessiveBotsCount {
+ get {
+ return ResourceManager.GetString("WarningExcessiveBotsCount", resourceCulture);
+ }
+ }
+
+ public static string PluginLoaded {
+ get {
+ return ResourceManager.GetString("PluginLoaded", resourceCulture);
+ }
+ }
+
+ public static string PluginLoading {
+ get {
+ return ResourceManager.GetString("PluginLoading", resourceCulture);
+ }
+ }
+
+ public static string NothingFound {
+ get {
+ return ResourceManager.GetString("NothingFound", resourceCulture);
+ }
+ }
+
+ public static string PluginsWarning {
+ get {
+ return ResourceManager.GetString("PluginsWarning", resourceCulture);
+ }
+ }
+
+ public static string PleaseWait {
+ get {
+ return ResourceManager.GetString("PleaseWait", resourceCulture);
+ }
+ }
+
+ public static string EnterCommand {
+ get {
+ return ResourceManager.GetString("EnterCommand", resourceCulture);
+ }
+ }
+
+ public static string Executing {
+ get {
+ return ResourceManager.GetString("Executing", resourceCulture);
+ }
+ }
+
+ public static string InteractiveConsoleEnabled {
+ get {
+ return ResourceManager.GetString("InteractiveConsoleEnabled", resourceCulture);
+ }
+ }
+
+ public static string BotGamesToRedeemInBackgroundCount {
+ get {
+ return ResourceManager.GetString("BotGamesToRedeemInBackgroundCount", resourceCulture);
+ }
+ }
+
+ public static string ErrorSingleInstanceRequired {
+ get {
+ return ResourceManager.GetString("ErrorSingleInstanceRequired", resourceCulture);
+ }
+ }
+
+ public static string BotHandledConfirmations {
+ get {
+ return ResourceManager.GetString("BotHandledConfirmations", resourceCulture);
+ }
+ }
+
+ public static string BotExtraIdlingCooldown {
+ get {
+ return ResourceManager.GetString("BotExtraIdlingCooldown", resourceCulture);
+ }
+ }
+
+ public static string UpdateCleanup {
+ get {
+ return ResourceManager.GetString("UpdateCleanup", resourceCulture);
+ }
+ }
+
+ public static string BotGeneratingSteamParentalCode {
+ get {
+ return ResourceManager.GetString("BotGeneratingSteamParentalCode", resourceCulture);
+ }
+ }
+
+ public static string IPCConfigChanged {
+ get {
+ return ResourceManager.GetString("IPCConfigChanged", resourceCulture);
+ }
+ }
+
+ public static string BotTradeOfferResult {
+ get {
+ return ResourceManager.GetString("BotTradeOfferResult", resourceCulture);
+ }
+ }
+
+ public static string BotInvalidPasswordDuringLogin {
+ get {
+ return ResourceManager.GetString("BotInvalidPasswordDuringLogin", resourceCulture);
+ }
+ }
+
+ public static string Result {
+ get {
+ return ResourceManager.GetString("Result", resourceCulture);
+ }
+ }
+
+ public static string WarningUnsupportedEnvironment {
+ get {
+ return ResourceManager.GetString("WarningUnsupportedEnvironment", resourceCulture);
+ }
+ }
+
+ public static string WarningUnknownCommandLineArgument {
+ get {
+ return ResourceManager.GetString("WarningUnknownCommandLineArgument", resourceCulture);
+ }
+ }
+
+ public static string ErrorConfigDirectoryNotFound {
+ get {
+ return ResourceManager.GetString("ErrorConfigDirectoryNotFound", resourceCulture);
+ }
+ }
+
+ public static string BotIdlingSelectedGames {
+ get {
+ return ResourceManager.GetString("BotIdlingSelectedGames", resourceCulture);
+ }
+ }
+
+ public static string AutomaticFileMigration {
+ get {
+ return ResourceManager.GetString("AutomaticFileMigration", resourceCulture);
+ }
+ }
+
+ public static string WarningWeakIPCPassword {
+ get {
+ return ResourceManager.GetString("WarningWeakIPCPassword", resourceCulture);
+ }
+ }
+
+ public static string WarningWeakSteamPassword {
+ get {
+ return ResourceManager.GetString("WarningWeakSteamPassword", resourceCulture);
+ }
+ }
+
+ public static string WarningWeakCryptKey {
+ get {
+ return ResourceManager.GetString("WarningWeakCryptKey", resourceCulture);
+ }
+ }
+
+ public static string WarningTooShortCryptKey {
+ get {
+ return ResourceManager.GetString("WarningTooShortCryptKey", resourceCulture);
+ }
+ }
+
+ public static string WarningDefaultCryptKeyUsedForHashing {
+ get {
+ return ResourceManager.GetString("WarningDefaultCryptKeyUsedForHashing", resourceCulture);
+ }
+ }
+
+ public static string WarningDefaultCryptKeyUsedForEncryption {
+ get {
+ return ResourceManager.GetString("WarningDefaultCryptKeyUsedForEncryption", resourceCulture);
+ }
+ }
+
+ public static string WarningRunningAsRoot {
+ get {
+ return ResourceManager.GetString("WarningRunningAsRoot", resourceCulture);
+ }
+ }
+
+ public static string WarningRunningInUnsupportedEnvironment {
+ get {
+ return ResourceManager.GetString("WarningRunningInUnsupportedEnvironment", resourceCulture);
+ }
+ }
+
+ public static string FetchingChecksumFromRemoteServer {
+ get {
+ return ResourceManager.GetString("FetchingChecksumFromRemoteServer", resourceCulture);
+ }
+ }
+
+ public static string VerifyingChecksumWithRemoteServer {
+ get {
+ return ResourceManager.GetString("VerifyingChecksumWithRemoteServer", resourceCulture);
+ }
+ }
+
+ public static string ChecksumMissing {
+ get {
+ return ResourceManager.GetString("ChecksumMissing", resourceCulture);
+ }
+ }
+
+ public static string ChecksumWrong {
+ get {
+ return ResourceManager.GetString("ChecksumWrong", resourceCulture);
+ }
+ }
+
+ public static string PatchingFiles {
+ get {
+ return ResourceManager.GetString("PatchingFiles", resourceCulture);
+ }
+ }
+
+ public static string UserInputCryptkey {
+ get {
+ return ResourceManager.GetString("UserInputCryptkey", resourceCulture);
+ }
+ }
+
+ public static string ErrorIPNotBanned {
+ get {
+ return ResourceManager.GetString("ErrorIPNotBanned", resourceCulture);
+ }
+ }
+
+ public static string WarningNoLicense {
+ get {
+ return ResourceManager.GetString("WarningNoLicense", resourceCulture);
}
}
}
diff --git a/ArchiSteamFarm/Localization/Strings.resx b/ArchiSteamFarm/Localization/Strings.resx
index fb52eb28f..5bf0f928b 100644
--- a/ArchiSteamFarm/Localization/Strings.resx
+++ b/ArchiSteamFarm/Localization/Strings.resx
@@ -603,10 +603,6 @@ Process uptime: {1}
Aborted!
-
- Matched a total of {0} sets this round.
- {0} will be replaced by number of sets traded
-
You're running more personal bot accounts than our upper recommended limit ({0}). Be advised that this setup is not supported and might cause various Steam-related issues, including account suspensions. Check out the FAQ for more details.
{0} will be replaced by our maximum recommended bots count (number)
@@ -744,4 +740,8 @@ Process uptime: {1}
The IP address {0} is not banned!
{0} will be replaced by an IP address which was requested to be unbanned from using IPC
+
+ You've attempted to use paid feature {0} but you don't have a valid LicenseID set in the ASF global config. Please review your configuration, as the functionality won't work without additional details.
+ {0} will be replaced by feature name (e.g. MatchActively)
+
diff --git a/ArchiSteamFarm/Plugins/Interfaces/IBotIdentity.cs b/ArchiSteamFarm/Plugins/Interfaces/IBotIdentity.cs
new file mode 100644
index 000000000..f9187835b
--- /dev/null
+++ b/ArchiSteamFarm/Plugins/Interfaces/IBotIdentity.cs
@@ -0,0 +1,39 @@
+// _ _ _ ____ _ _____
+// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
+// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
+// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
+// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
+// |
+// Copyright 2015-2022 Ł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.Threading.Tasks;
+using ArchiSteamFarm.Steam;
+using JetBrains.Annotations;
+using SteamKit2;
+
+namespace ArchiSteamFarm.Plugins.Interfaces;
+
+[PublicAPI]
+public interface IBotIdentity : IPlugin {
+ ///
+ /// ASF will call this method when bot receives its own identity information.
+ ///
+ /// Bot object related to this callback.
+ /// Full data received by ASF in the callback that relates to this bot (Steam) account.
+ /// Parsed nickname set for this bot (Steam) account.
+ /// Parsed hash of the avatar of this bot (Steam) account, as hex.
+ Task OnSelfPersonaState(Bot bot, SteamFriends.PersonaStateCallback data, string? nickname, string? avatarHash);
+}
diff --git a/ArchiSteamFarm/Plugins/PluginsCore.cs b/ArchiSteamFarm/Plugins/PluginsCore.cs
index 11647a688..abdc28e7b 100644
--- a/ArchiSteamFarm/Plugins/PluginsCore.cs
+++ b/ArchiSteamFarm/Plugins/PluginsCore.cs
@@ -453,6 +453,21 @@ public static class PluginsCore {
}
}
+ internal static async Task OnSelfPersonaState(Bot bot, SteamFriends.PersonaStateCallback data, string? nickname, string? avatarHash) {
+ ArgumentNullException.ThrowIfNull(bot);
+ ArgumentNullException.ThrowIfNull(data);
+
+ if ((ActivePlugins == null) || (ActivePlugins.Count == 0)) {
+ return;
+ }
+
+ try {
+ await Utilities.InParallel(ActivePlugins.OfType().Select(plugin => plugin.OnSelfPersonaState(bot, data, nickname, avatarHash))).ConfigureAwait(false);
+ } catch (Exception e) {
+ ASF.ArchiLogger.LogGenericException(e);
+ }
+ }
+
internal static async Task OnBotMessage(Bot bot, ulong steamID, string message) {
ArgumentNullException.ThrowIfNull(bot);
diff --git a/ArchiSteamFarm/Steam/Bot.cs b/ArchiSteamFarm/Steam/Bot.cs
index 5cce06650..03a8c6631 100644
--- a/ArchiSteamFarm/Steam/Bot.cs
+++ b/ArchiSteamFarm/Steam/Bot.cs
@@ -214,6 +214,7 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
[PublicAPI]
public ECurrencyCode WalletCurrency { get; private set; }
+ internal byte HeartBeatFailures { get; private set; }
internal bool PlayingBlocked { get; private set; }
internal bool PlayingWasBlocked { get; private set; }
@@ -225,7 +226,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
private Timer? ConnectionFailureTimer;
private bool FirstTradeSent;
private Timer? GamesRedeemerInBackgroundTimer;
- private byte HeartBeatFailures;
private EResult LastLogOnResult;
private DateTime LastLogonSessionReplaced;
private bool LibraryLocked;
@@ -233,7 +233,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
private ulong MasterChatGroupID;
private Timer? PlayingWasBlockedTimer;
private bool ReconnectOnUserInitiated;
- private RemoteCommunication? RemoteCommunication;
private bool SendCompleteTypesScheduled;
private Timer? SendItemsTimer;
private bool SteamParentalActive;
@@ -345,7 +344,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
ConnectionFailureTimer?.Dispose();
GamesRedeemerInBackgroundTimer?.Dispose();
PlayingWasBlockedTimer?.Dispose();
- RemoteCommunication?.Dispose();
SendItemsTimer?.Dispose();
SteamSaleEvent?.Dispose();
}
@@ -382,10 +380,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
await SendItemsTimer.DisposeAsync().ConfigureAwait(false);
}
- if (RemoteCommunication != null) {
- await RemoteCommunication.DisposeAsync().ConfigureAwait(false);
- }
-
if (SteamSaleEvent != null) {
await SteamSaleEvent.DisposeAsync().ConfigureAwait(false);
}
@@ -1946,10 +1940,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
}
HeartBeatFailures = 0;
-
- if (RemoteCommunication != null) {
- Utilities.InBackground(RemoteCommunication.OnHeartBeat);
- }
} catch (Exception e) {
ArchiLogger.LogGenericDebuggingException(e);
@@ -2097,16 +2087,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
SteamSaleEvent = new SteamSaleEvent(this);
}
- if (RemoteCommunication != null) {
- await RemoteCommunication.DisposeAsync().ConfigureAwait(false);
-
- RemoteCommunication = null;
- }
-
- if (BotConfig.RemoteCommunication > BotConfig.ERemoteCommunication.None) {
- RemoteCommunication = new RemoteCommunication(this);
- }
-
await PluginsCore.OnBotInitModules(this, BotConfig.AdditionalProperties).ConfigureAwait(false);
}
@@ -2862,10 +2842,6 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
Utilities.InBackground(InitializeFamilySharing);
- if (RemoteCommunication != null) {
- Utilities.InBackground(RemoteCommunication.OnLoggedOn);
- }
-
ResetPersonaState();
if (BotConfig.SteamMasterClanID != 0) {
@@ -2880,6 +2856,10 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
);
}
+ if (BotConfig.RemoteCommunication.HasFlag(BotConfig.ERemoteCommunication.SteamGroup)) {
+ Utilities.InBackground(() => ArchiWebHandler.JoinGroup(SharedInfo.ASFGroupSteamID));
+ }
+
if (CardsFarmer.Paused) {
// Emit initial game playing status in this case
Utilities.InBackground(ResetGamesPlayed);
@@ -3013,13 +2993,15 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
);
}
- private void OnPersonaState(SteamFriends.PersonaStateCallback callback) {
+ private async void OnPersonaState(SteamFriends.PersonaStateCallback callback) {
ArgumentNullException.ThrowIfNull(callback);
if (callback.FriendID != SteamID) {
return;
}
+ Nickname = callback.Name;
+
string? avatarHash = null;
if ((callback.AvatarHash?.Length > 0) && callback.AvatarHash.Any(static singleByte => singleByte != 0)) {
@@ -3033,11 +3015,8 @@ public sealed class Bot : IAsyncDisposable, IDisposable {
}
AvatarHash = avatarHash;
- Nickname = callback.Name;
- if (RemoteCommunication != null) {
- Utilities.InBackground(() => RemoteCommunication.OnPersonaState(callback.Name, avatarHash));
- }
+ await PluginsCore.OnSelfPersonaState(this, callback, Nickname, AvatarHash).ConfigureAwait(false);
}
private async void OnPlayingSessionState(ArchiHandler.PlayingSessionStateCallback callback) {
diff --git a/ArchiSteamFarm/Steam/Data/InventoryResponse.cs b/ArchiSteamFarm/Steam/Data/InventoryResponse.cs
index e6f126104..15bd8386d 100644
--- a/ArchiSteamFarm/Steam/Data/InventoryResponse.cs
+++ b/ArchiSteamFarm/Steam/Data/InventoryResponse.cs
@@ -37,7 +37,7 @@ namespace ArchiSteamFarm.Steam.Data;
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
internal sealed class InventoryResponse : OptionalResultResponse {
[JsonProperty("assets", Required = Required.DisallowNull)]
- internal readonly ImmutableHashSet Assets = ImmutableHashSet.Empty;
+ internal readonly ImmutableList Assets = ImmutableList.Empty;
[JsonProperty("descriptions", Required = Required.DisallowNull)]
internal readonly ImmutableHashSet Descriptions = ImmutableHashSet.Empty;
diff --git a/ArchiSteamFarm/Steam/Exchange/Trading.cs b/ArchiSteamFarm/Steam/Exchange/Trading.cs
index 36ddffefa..4e2738b43 100644
--- a/ArchiSteamFarm/Steam/Exchange/Trading.cs
+++ b/ArchiSteamFarm/Steam/Exchange/Trading.cs
@@ -262,7 +262,7 @@ public sealed class Trading : IDisposable {
return tradableState;
}
- internal static HashSet GetTradableItemsFromInventory(IReadOnlyCollection inventory, IDictionary classIDs) {
+ internal static HashSet GetTradableItemsFromInventory(IReadOnlyCollection inventory, IDictionary classIDs, bool randomize = false) {
if ((inventory == null) || (inventory.Count == 0)) {
throw new ArgumentNullException(nameof(inventory));
}
@@ -273,7 +273,16 @@ public sealed class Trading : IDisposable {
HashSet result = new();
- foreach (Asset item in inventory.Where(static item => item.Tradable)) {
+ IEnumerable items = inventory;
+
+ // Randomization helps to decrease "items no longer available" in regards to sending offers to other users
+ if (randomize) {
+#pragma warning disable CA5394 // This call isn't used in a security-sensitive manner
+ items = items.OrderBy(static _ => Random.Shared.Next());
+#pragma warning restore CA5394 // This call isn't used in a security-sensitive manner
+ }
+
+ foreach (Asset item in items.Where(static item => item.Tradable)) {
if (!classIDs.TryGetValue(item.ClassID, out uint amount)) {
continue;
}
diff --git a/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs b/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs
index 693c4aa99..b3f554499 100644
--- a/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs
+++ b/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs
@@ -48,10 +48,9 @@ using SteamKit2;
namespace ArchiSteamFarm.Steam.Integration;
public sealed class ArchiWebHandler : IDisposable {
- internal const ushort MaxItemsInSingleInventoryRequest = 5000;
-
private const string EconService = "IEconService";
private const string LoyaltyRewardsService = "ILoyaltyRewardsService";
+ private const ushort MaxItemsInSingleInventoryRequest = 5000;
private const byte MinimumSessionValidityInSeconds = 10;
private const string SteamAppsService = "ISteamApps";
private const string SteamUserAuthService = "ISteamUserAuth";
diff --git a/ArchiSteamFarm/Storage/GlobalConfig.cs b/ArchiSteamFarm/Storage/GlobalConfig.cs
index 5587c0335..e11f3dee8 100644
--- a/ArchiSteamFarm/Storage/GlobalConfig.cs
+++ b/ArchiSteamFarm/Storage/GlobalConfig.cs
@@ -129,6 +129,9 @@ public sealed class GlobalConfig {
[PublicAPI]
public static readonly ImmutableHashSet DefaultBlacklist = ImmutableHashSet.Empty;
+ [PublicAPI]
+ public static readonly Guid? DefaultLicenseID;
+
private static readonly ImmutableHashSet ForbiddenIPCPasswordPhrases = ImmutableHashSet.Create(StringComparer.InvariantCultureIgnoreCase, "ipc", "api", "gui", "asf-ui", "asf-gui");
[JsonIgnore]
@@ -237,6 +240,9 @@ public sealed class GlobalConfig {
[JsonProperty(Required = Required.DisallowNull)]
public ArchiCryptoHelper.EHashingMethod IPCPasswordFormat { get; private set; } = DefaultIPCPasswordFormat;
+ [JsonProperty]
+ public Guid? LicenseID { get; private set; } = DefaultLicenseID;
+
[JsonProperty(Required = Required.DisallowNull)]
[Range(byte.MinValue, byte.MaxValue)]
public byte LoginLimiterDelay { get; private set; } = DefaultLoginLimiterDelay;
@@ -375,6 +381,9 @@ public sealed class GlobalConfig {
[UsedImplicitly]
public bool ShouldSerializeIPCPasswordFormat() => !Saving || (IPCPasswordFormat != DefaultIPCPasswordFormat);
+ [UsedImplicitly]
+ public bool ShouldSerializeLicenseID() => !Saving || ((LicenseID != DefaultLicenseID) && (LicenseID != Guid.Empty));
+
[UsedImplicitly]
public bool ShouldSerializeLoginLimiterDelay() => !Saving || (LoginLimiterDelay != DefaultLoginLimiterDelay);
diff --git a/Dockerfile b/Dockerfile
index a12314cc5..2ed7e778c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,9 +4,10 @@ FROM --platform=$BUILDPLATFORM node:lts${IMAGESUFFIX} AS build-node
WORKDIR /app/ASF-ui
COPY ASF-ui .
COPY .git/modules/ASF-ui /app/.git/modules/ASF-ui
-RUN echo "node: $(node --version)" && \
- echo "npm: $(npm --version)" && \
- npm ci --no-progress && \
+RUN set -eu; \
+ echo "node: $(node --version)"; \
+ echo "npm: $(npm --version)"; \
+ npm ci --no-progress; \
npm run deploy --no-progress
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0${IMAGESUFFIX} AS build-dotnet
@@ -17,30 +18,43 @@ ARG TARGETOS
ENV DOTNET_CLI_TELEMETRY_OPTOUT true
ENV DOTNET_NOLOGO true
ENV NET_CORE_VERSION net7.0
+ENV PLUGINS ArchiSteamFarm.OfficialPlugins.ItemsMatcher
ENV STEAM_TOKEN_DUMPER_NAME ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
WORKDIR /app
COPY --from=build-node /app/ASF-ui/dist ASF-ui/dist
COPY ArchiSteamFarm ArchiSteamFarm
+COPY ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.ItemsMatcher
COPY ArchiSteamFarm.OfficialPlugins.SteamTokenDumper ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
COPY resources resources
COPY .editorconfig .editorconfig
COPY Directory.Build.props Directory.Build.props
COPY Directory.Packages.props Directory.Packages.props
COPY LICENSE.txt LICENSE.txt
-RUN dotnet --info && \
+RUN set -eu; \
+ dotnet --info; \
+ \
case "$TARGETOS" in \
"linux") ;; \
*) echo "ERROR: Unsupported OS: ${TARGETOS}"; exit 1 ;; \
- esac && \
+ esac; \
+ \
case "$TARGETARCH" in \
"amd64") asf_variant="${TARGETOS}-x64" ;; \
"arm") asf_variant="${TARGETOS}-${TARGETARCH}" ;; \
"arm64") asf_variant="${TARGETOS}-${TARGETARCH}" ;; \
*) echo "ERROR: Unsupported CPU architecture: ${TARGETARCH}"; exit 1 ;; \
- esac && \
- if [ -n "${STEAM_TOKEN_DUMPER_TOKEN-}" ] && [ -f "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs" ]; then sed -i "s/STEAM_TOKEN_DUMPER_TOKEN/${STEAM_TOKEN_DUMPER_TOKEN}/g" "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs"; dotnet publish "${STEAM_TOKEN_DUMPER_NAME}" -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}" -p:ASFVariant=docker -p:ContinuousIntegrationBuild=true -p:UseAppHost=false -r "$asf_variant" --nologo --no-self-contained; fi && \
- dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/result" -p:ASFVariant=docker -p:ContinuousIntegrationBuild=true -p:UseAppHost=false -r "$asf_variant" --nologo --no-self-contained && \
- if [ -d "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}" ]; then mkdir -p "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; cp -pR "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/"* "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; fi
+ esac; \
+ \
+ dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/result" -p:ASFVariant=docker -p:ContinuousIntegrationBuild=true -p:UseAppHost=false -r "$asf_variant" --nologo --no-self-contained; \
+ \
+ if [ -n "${STEAM_TOKEN_DUMPER_TOKEN-}" ] && [ -f "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs" ]; then \
+ sed -i "s/STEAM_TOKEN_DUMPER_TOKEN/${STEAM_TOKEN_DUMPER_TOKEN}/g" "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs"; \
+ dotnet publish "${STEAM_TOKEN_DUMPER_NAME}" -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}" -p:ASFVariant=docker -p:ContinuousIntegrationBuild=true -p:UseAppHost=false -r "$asf_variant" --nologo --no-self-contained; \
+ fi; \
+ \
+ for plugin in $PLUGINS; do \
+ dotnet publish "$plugin" -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/result/plugins/$plugin" -p:ASFVariant=docker -p:ContinuousIntegrationBuild=true -p:UseAppHost=false -r "$asf_variant" --nologo --no-self-contained; \
+ done
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:7.0${IMAGESUFFIX} AS runtime
ENV ASF_USER asf
@@ -62,8 +76,9 @@ EXPOSE 1242
WORKDIR /app
COPY --from=build-dotnet /app/out/result .
-RUN groupadd -r -g 1000 asf && \
- useradd -r -d /app -g 1000 -u 1000 asf && \
+RUN set -eu; \
+ groupadd -r -g 1000 asf; \
+ useradd -r -d /app -g 1000 -u 1000 asf; \
chown -hR asf:asf /app
VOLUME ["/app/config", "/app/logs"]
diff --git a/Dockerfile.Service b/Dockerfile.Service
index 474414d6e..e2c14aa8f 100644
--- a/Dockerfile.Service
+++ b/Dockerfile.Service
@@ -4,9 +4,10 @@ FROM --platform=$BUILDPLATFORM node:lts${IMAGESUFFIX} AS build-node
WORKDIR /app/ASF-ui
COPY ASF-ui .
COPY .git/modules/ASF-ui /app/.git/modules/ASF-ui
-RUN echo "node: $(node --version)" && \
- echo "npm: $(npm --version)" && \
- npm ci --no-progress && \
+RUN set -eu; \
+ echo "node: $(node --version)"; \
+ echo "npm: $(npm --version)"; \
+ npm ci --no-progress; \
npm run deploy --no-progress
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0${IMAGESUFFIX} AS build-dotnet
@@ -17,30 +18,43 @@ ARG TARGETOS
ENV DOTNET_CLI_TELEMETRY_OPTOUT true
ENV DOTNET_NOLOGO true
ENV NET_CORE_VERSION net7.0
+ENV PLUGINS ArchiSteamFarm.OfficialPlugins.ItemsMatcher
ENV STEAM_TOKEN_DUMPER_NAME ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
WORKDIR /app
COPY --from=build-node /app/ASF-ui/dist ASF-ui/dist
COPY ArchiSteamFarm ArchiSteamFarm
+COPY ArchiSteamFarm.OfficialPlugins.ItemsMatcher ArchiSteamFarm.OfficialPlugins.ItemsMatcher
COPY ArchiSteamFarm.OfficialPlugins.SteamTokenDumper ArchiSteamFarm.OfficialPlugins.SteamTokenDumper
COPY resources resources
COPY .editorconfig .editorconfig
COPY Directory.Build.props Directory.Build.props
COPY Directory.Packages.props Directory.Packages.props
COPY LICENSE.txt LICENSE.txt
-RUN dotnet --info && \
+RUN set -eu; \
+ dotnet --info; \
+ \
case "$TARGETOS" in \
"linux") ;; \
*) echo "ERROR: Unsupported OS: ${TARGETOS}"; exit 1 ;; \
- esac && \
+ esac; \
+ \
case "$TARGETARCH" in \
"amd64") asf_variant="${TARGETOS}-x64" ;; \
"arm") asf_variant="${TARGETOS}-${TARGETARCH}" ;; \
"arm64") asf_variant="${TARGETOS}-${TARGETARCH}" ;; \
*) echo "ERROR: Unsupported CPU architecture: ${TARGETARCH}"; exit 1 ;; \
- esac && \
- if [ -n "${STEAM_TOKEN_DUMPER_TOKEN-}" ] && [ -f "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs" ]; then sed -i "s/STEAM_TOKEN_DUMPER_TOKEN/${STEAM_TOKEN_DUMPER_TOKEN}/g" "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs"; dotnet publish "${STEAM_TOKEN_DUMPER_NAME}" -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}" "-p:ASFVariant=${asf_variant}" -p:ContinuousIntegrationBuild=true -p:UseAppHost=false -r "$asf_variant" --nologo --no-self-contained; fi && \
- dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/result" "-p:ASFVariant=${asf_variant}" -p:ContinuousIntegrationBuild=true -p:PublishSingleFile=true -p:PublishTrimmed=true -r "$asf_variant" --nologo --self-contained && \
- if [ -d "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}" ]; then mkdir -p "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; cp -pR "out/${STEAM_TOKEN_DUMPER_NAME}/${NET_CORE_VERSION}/"* "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}"; fi
+ esac; \
+ \
+ dotnet publish ArchiSteamFarm -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/result" "-p:ASFVariant=${asf_variant}" -p:ContinuousIntegrationBuild=true -p:PublishSingleFile=true -p:PublishTrimmed=true -r "$asf_variant" --nologo --self-contained; \
+ \
+ if [ -n "${STEAM_TOKEN_DUMPER_TOKEN-}" ] && [ -f "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs" ]; then \
+ sed -i "s/STEAM_TOKEN_DUMPER_TOKEN/${STEAM_TOKEN_DUMPER_TOKEN}/g" "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs"; \
+ dotnet publish "${STEAM_TOKEN_DUMPER_NAME}" -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/result/plugins/${STEAM_TOKEN_DUMPER_NAME}" "-p:ASFVariant=${asf_variant}" -p:ContinuousIntegrationBuild=true -p:UseAppHost=false -r "$asf_variant" --nologo --no-self-contained; \
+ fi; \
+ \
+ for plugin in $PLUGINS; do \
+ dotnet publish "$plugin" -c "$CONFIGURATION" -f "$NET_CORE_VERSION" -o "out/result/plugins/$plugin" "-p:ASFVariant=${asf_variant}" -p:ContinuousIntegrationBuild=true -p:UseAppHost=false -r "$asf_variant" --nologo --no-self-contained; \
+ done
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime-deps:7.0${IMAGESUFFIX} AS runtime
ENV ASF_USER asf
@@ -62,8 +76,9 @@ EXPOSE 1242
WORKDIR /app
COPY --from=build-dotnet /app/out/result .
-RUN groupadd -r -g 1000 asf && \
- useradd -r -d /app -g 1000 -u 1000 asf && \
+RUN set -eu; \
+ groupadd -r -g 1000 asf; \
+ useradd -r -d /app -g 1000 -u 1000 asf; \
chown -hR asf:asf /app
VOLUME ["/app/config", "/app/logs"]
diff --git a/cc.sh b/cc.sh
index 9da4d0a8f..ae8ab8c74 100755
--- a/cc.sh
+++ b/cc.sh
@@ -11,6 +11,7 @@ CONFIGURATION="Release"
OUT="out"
OUT_ASF="${OUT}/result"
OUT_STD="${OUT}/${STEAM_TOKEN_DUMPER_NAME}"
+PLUGINS="${MAIN_PROJECT}.OfficialPlugins.ItemsMatcher"
ANALYSIS=1
ASF_UI=1
@@ -132,6 +133,8 @@ if [ "$TEST" -eq 1 ]; then
dotnet test "$TESTS_PROJECT" $DOTNET_FLAGS
fi
+echo "INFO: Building ${MAIN_PROJECT}..."
+
dotnet publish "$MAIN_PROJECT" -o "$OUT_ASF" $DOTNET_FLAGS $PUBLISH_FLAGS
if [ -n "${STEAM_TOKEN_DUMPER_TOKEN-}" ] && [ -f "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs" ] && command -v git >/dev/null; then
@@ -139,15 +142,19 @@ if [ -n "${STEAM_TOKEN_DUMPER_TOKEN-}" ] && [ -f "${STEAM_TOKEN_DUMPER_NAME}/Sha
sed "s/STEAM_TOKEN_DUMPER_TOKEN/${STEAM_TOKEN_DUMPER_TOKEN}/g" "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs" > "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs.new";
mv "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs.new" "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs"
- dotnet publish "$STEAM_TOKEN_DUMPER_NAME" -o "$OUT_STD" $DOTNET_FLAGS $PUBLISH_FLAGS
- git checkout -- "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs"
+ echo "INFO: Building ${STEAM_TOKEN_DUMPER_NAME}..."
- rm -rf "${OUT_ASF}/plugins/${STEAM_TOKEN_DUMPER_NAME}"
- mkdir -p "${OUT_ASF}/plugins/${STEAM_TOKEN_DUMPER_NAME}"
- cp -pR "${OUT_STD}/"* "${OUT_ASF}/plugins/${STEAM_TOKEN_DUMPER_NAME}"
+ dotnet publish "$STEAM_TOKEN_DUMPER_NAME" -o "${OUT_ASF}/plugins/${STEAM_TOKEN_DUMPER_NAME}" $DOTNET_FLAGS $PUBLISH_FLAGS
+ git checkout -- "${STEAM_TOKEN_DUMPER_NAME}/SharedInfo.cs"
else
echo "WARNING: ${STEAM_TOKEN_DUMPER_NAME} dependencies are missing, skipping build of ${STEAM_TOKEN_DUMPER_NAME}..."
fi
+for plugin in $PLUGINS; do
+ echo "INFO: Building ${plugin}..."
+
+ dotnet publish "$plugin" -o "${OUT_ASF}/plugins/${plugin}" $DOTNET_FLAGS $PUBLISH_FLAGS
+done
+
echo
echo "SUCCESS: Compilation finished successfully! :)"