mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2025-12-29 04:30:47 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28fa7ac538 | ||
|
|
3292816967 | ||
|
|
19aa60cccd | ||
|
|
0efb3eea8e | ||
|
|
1a6e554ee9 | ||
|
|
8587667e27 | ||
|
|
0c79b17163 | ||
|
|
0a5ac68df4 | ||
|
|
64eda2b44f | ||
|
|
3e978f44e7 | ||
|
|
370ab4f5d0 | ||
|
|
8e84dd0af6 | ||
|
|
f2875b1b2b | ||
|
|
702a525893 | ||
|
|
c4c11cf61f | ||
|
|
06b1b8deeb | ||
|
|
0beb000d4b | ||
|
|
acc871e609 | ||
|
|
e8545176e7 | ||
|
|
532a47bda5 | ||
|
|
ddc2d956ba | ||
|
|
563f57e3aa | ||
|
|
0a973cefd2 | ||
|
|
2563ade159 |
@@ -15,9 +15,6 @@ ArchiSteamFarm/logs
|
||||
# Ignore standard out folders for publishing
|
||||
**/out
|
||||
|
||||
# Ignore crowdin CLI secret (if exists)
|
||||
tools/ArchiCrowdin/crowdin_identity.yml
|
||||
|
||||
# _ ____ _____ ____ _
|
||||
# / \ / ___|| ___| | _ \ ___ ___| | _____ _ __
|
||||
# / _ \ \___ \| |_ _____| | | |/ _ \ / __| |/ / _ \ '__|
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -7,7 +7,7 @@ contact_links:
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/wiki/Localization
|
||||
about: Please use our crowdin platform.
|
||||
- name: Support question or technical issue
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/blob/master/SUPPORT.md
|
||||
url: https://github.com/JustArchiNET/ArchiSteamFarm/blob/master/.github/SUPPORT.md
|
||||
about: Please review our support guidelines.
|
||||
- name: Negative feedback, complaints and demands
|
||||
url: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
||||
|
||||
0
SECURITY.md → .github/SECURITY.md
vendored
0
SECURITY.md → .github/SECURITY.md
vendored
0
SUPPORT.md → .github/SUPPORT.md
vendored
0
SUPPORT.md → .github/SUPPORT.md
vendored
31
.github/lock.yml
vendored
31
.github/lock.yml
vendored
@@ -1,31 +0,0 @@
|
||||
# Configuration for lock-threads - https://github.com/dessant/lock-threads
|
||||
|
||||
# Number of days of inactivity before a closed issue or pull request is locked
|
||||
daysUntilLock: 30
|
||||
|
||||
# Issues and pull requests with these labels will not be locked. Set to `[]` to disable
|
||||
exemptLabels: []
|
||||
|
||||
# Label to add before locking, such as `outdated`. Set to `false` to disable
|
||||
lockLabel: false
|
||||
|
||||
# Comment to post before locking. Set to `false` to disable
|
||||
lockComment: false
|
||||
|
||||
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
||||
setLockReason: true
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
# only: issues
|
||||
|
||||
# Optionally, specify configuration settings just for `issues` or `pulls`
|
||||
# issues:
|
||||
# exemptLabels:
|
||||
# - help-wanted
|
||||
# lockLabel: outdated
|
||||
|
||||
# pulls:
|
||||
# daysUntilLock: 30
|
||||
|
||||
# Repository to extend settings from
|
||||
# _extends: repo
|
||||
16
.github/workflows/lock.yml
vendored
Normal file
16
.github/workflows/lock.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: ASF-lock-threads
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 1 * * *'
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Lock inactive threads
|
||||
uses: dessant/lock-threads@v2
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-lock-inactive-days: 30
|
||||
pr-lock-inactive-days: 30
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -15,9 +15,6 @@ ArchiSteamFarm/logs
|
||||
# Ignore standard out folders for publishing
|
||||
**/out
|
||||
|
||||
# Ignore crowdin CLI secret (if exists)
|
||||
tools/ArchiCrowdin/crowdin_identity.yml
|
||||
|
||||
# _ _
|
||||
# | | (_) _ __ _ _ __ __
|
||||
# | | | || '_ \ | | | |\ \/ /
|
||||
|
||||
2
ASF-ui
2
ASF-ui
Submodule ASF-ui updated: 6e066d0edc...74f056221d
@@ -138,6 +138,28 @@ namespace ArchiSteamFarm.Tests {
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameAbrynosWasWrongNeutralAccept() {
|
||||
HashSet<Steam.Asset> inventory = new HashSet<Steam.Asset> {
|
||||
CreateItem(1),
|
||||
CreateItem(2, 2),
|
||||
CreateItem(3),
|
||||
CreateItem(4),
|
||||
CreateItem(5)
|
||||
};
|
||||
|
||||
HashSet<Steam.Asset> itemsToGive = new HashSet<Steam.Asset> {
|
||||
CreateItem(2)
|
||||
};
|
||||
|
||||
HashSet<Steam.Asset> itemsToReceive = new HashSet<Steam.Asset> {
|
||||
CreateItem(3)
|
||||
};
|
||||
|
||||
Assert.IsTrue(IsFairExchange(itemsToGive, itemsToReceive));
|
||||
Assert.IsTrue(IsTradeNeutralOrBetter(inventory, itemsToGive, itemsToReceive));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SingleGameDonationAccept() {
|
||||
HashSet<Steam.Asset> inventory = new HashSet<Steam.Asset> {
|
||||
|
||||
@@ -286,6 +286,8 @@ namespace ArchiSteamFarm {
|
||||
try {
|
||||
inventory = await Bot.ArchiWebHandler.GetInventoryAsync(Bot.SteamID, appID, contextID).Where(item => item.Tradable && filterFunction(item)).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException e) {
|
||||
Bot.ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
return (false, string.Format(Strings.WarningFailedWithError, e.Message));
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<PackageReference Include="CryptSharpStandard" Version="1.0.0" />
|
||||
<PackageReference Include="Humanizer" Version="2.8.26" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" />
|
||||
<PackageReference Include="Markdig.Signed" Version="0.20.0" />
|
||||
<PackageReference Include="Markdig.Signed" Version="0.21.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Nito.AsyncEx.Coordination" Version="5.0.0" />
|
||||
<PackageReference Include="NLog" Version="4.7.3" />
|
||||
@@ -35,7 +35,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.7" />
|
||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.7.0" />
|
||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
@@ -48,8 +48,8 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="3.1.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Configuration" Version="3.1.7" />
|
||||
<Reference Include="System.Net.Http">
|
||||
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\System.Net.Http.dll</HintPath>
|
||||
</Reference>
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace ArchiSteamFarm {
|
||||
private const char DefaultBackgroundKeysRedeemerSeparator = '\t';
|
||||
private const byte LoginCooldownInMinutes = 25; // Captcha disappears after around 20 minutes, so we make it 25
|
||||
private const uint LoginID = 1242; // This must be the same for all ASF bots and all ASF processes
|
||||
private const byte MaxInvalidPasswordFailures = WebBrowser.MaxTries; // Max InvalidPassword failures in a row before we determine that our password is invalid (because Steam wrongly returns those, of course)
|
||||
private const ushort MaxMessageLength = 5000; // This is a limitation enforced by Steam
|
||||
private const byte MaxTwoFactorCodeFailures = WebBrowser.MaxTries; // Max TwoFactorCodeMismatch failures in a row before we determine that our 2FA credentials are invalid (because Steam wrongly returns those, of course)
|
||||
private const byte RedeemCooldownInHours = 1; // 1 hour since first redeem attempt, this is a limitation enforced by Steam
|
||||
@@ -209,6 +210,7 @@ namespace ArchiSteamFarm {
|
||||
private bool FirstTradeSent;
|
||||
private Timer GamesRedeemerInBackgroundTimer;
|
||||
private byte HeartBeatFailures;
|
||||
private byte InvalidPasswordFailures;
|
||||
private EResult LastLogOnResult;
|
||||
private DateTime LastLogonSessionReplaced;
|
||||
private bool LibraryLocked;
|
||||
@@ -2183,18 +2185,19 @@ namespace ArchiSteamFarm {
|
||||
|
||||
switch (lastLogOnResult) {
|
||||
case EResult.AccountDisabled:
|
||||
case EResult.InvalidPassword when string.IsNullOrEmpty(BotDatabase.LoginKey):
|
||||
// Do not attempt to reconnect, those failures are permanent
|
||||
return;
|
||||
case EResult.InvalidPassword:
|
||||
case EResult.InvalidPassword when !string.IsNullOrEmpty(BotDatabase.LoginKey):
|
||||
BotDatabase.LoginKey = null;
|
||||
ArchiLogger.LogGenericInfo(Strings.BotRemovedExpiredLoginKey);
|
||||
|
||||
break;
|
||||
case EResult.InvalidPassword:
|
||||
case EResult.NoConnection:
|
||||
case EResult.ServiceUnavailable:
|
||||
case EResult.Timeout:
|
||||
case EResult.TryAnotherCM:
|
||||
case EResult.TwoFactorCodeMismatch:
|
||||
await Task.Delay(5000).ConfigureAwait(false);
|
||||
|
||||
break;
|
||||
@@ -2483,7 +2486,6 @@ namespace ArchiSteamFarm {
|
||||
|
||||
switch (callback.Result) {
|
||||
case EResult.AccountDisabled:
|
||||
case EResult.InvalidPassword when string.IsNullOrEmpty(BotDatabase.LoginKey):
|
||||
// Those failures are permanent, we should Stop() the bot if any of those happen
|
||||
ArchiLogger.LogGenericWarning(string.Format(Strings.BotUnableToLogin, callback.Result, callback.ExtendedResult));
|
||||
Stop();
|
||||
@@ -2522,7 +2524,7 @@ namespace ArchiSteamFarm {
|
||||
ArchiLogger.LogGenericInfo(string.Format(Strings.BotLoggedOn, SteamID + (!string.IsNullOrEmpty(callback.VanityURL) ? "/" + callback.VanityURL : "")));
|
||||
|
||||
// Old status for these doesn't matter, we'll update them if needed
|
||||
TwoFactorCodeFailures = 0;
|
||||
InvalidPasswordFailures = TwoFactorCodeFailures = 0;
|
||||
LibraryLocked = PlayingBlocked = false;
|
||||
|
||||
if (PlayingWasBlocked && (PlayingWasBlockedTimer == null)) {
|
||||
@@ -2659,17 +2661,25 @@ namespace ArchiSteamFarm {
|
||||
case EResult.TwoFactorCodeMismatch:
|
||||
ArchiLogger.LogGenericWarning(string.Format(Strings.BotUnableToLogin, callback.Result, callback.ExtendedResult));
|
||||
|
||||
if ((callback.Result == EResult.TwoFactorCodeMismatch) && HasMobileAuthenticator) {
|
||||
if (++TwoFactorCodeFailures >= MaxTwoFactorCodeFailures) {
|
||||
switch (callback.Result) {
|
||||
case EResult.InvalidPassword when string.IsNullOrEmpty(BotDatabase.LoginKey) && (++InvalidPasswordFailures >= MaxInvalidPasswordFailures):
|
||||
InvalidPasswordFailures = 0;
|
||||
ArchiLogger.LogGenericError(string.Format(Strings.BotInvalidPasswordDuringLogin, MaxInvalidPasswordFailures));
|
||||
Stop();
|
||||
|
||||
break;
|
||||
case EResult.TwoFactorCodeMismatch when HasMobileAuthenticator && (++TwoFactorCodeFailures >= MaxTwoFactorCodeFailures):
|
||||
TwoFactorCodeFailures = 0;
|
||||
ArchiLogger.LogGenericError(string.Format(Strings.BotInvalidAuthenticatorDuringLogin, MaxTwoFactorCodeFailures));
|
||||
Stop();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
// Unexpected result, shutdown immediately
|
||||
ArchiLogger.LogGenericError(string.Format(Strings.WarningUnknownValuePleaseReport, nameof(callback.Result), callback.Result));
|
||||
ArchiLogger.LogGenericError(string.Format(Strings.BotUnableToLogin, callback.Result, callback.ExtendedResult));
|
||||
Stop();
|
||||
|
||||
|
||||
@@ -2864,7 +2864,9 @@ namespace ArchiSteamFarm {
|
||||
completeSuccess = false;
|
||||
}
|
||||
}
|
||||
} catch (HttpRequestException) {
|
||||
} catch (HttpRequestException e) {
|
||||
Bot.ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
completeSuccess = false;
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
18
ArchiSteamFarm/Localization/Strings.Designer.cs
generated
18
ArchiSteamFarm/Localization/Strings.Designer.cs
generated
@@ -375,6 +375,15 @@ namespace ArchiSteamFarm.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wyszukuje zlokalizowany ciąg podobny do ciągu Received InvalidPassword error code {0} times in a row. Your password for this account is most likely wrong, aborting!.
|
||||
/// </summary>
|
||||
public static string BotInvalidPasswordDuringLogin {
|
||||
get {
|
||||
return ResourceManager.GetString("BotInvalidPasswordDuringLogin", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wyszukuje zlokalizowany ciąg podobny do ciągu Bot has level {0}..
|
||||
/// </summary>
|
||||
@@ -691,6 +700,15 @@ namespace ArchiSteamFarm.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wyszukuje zlokalizowany ciąg podobny do ciągu The trade offer {0} is determined to be {1} due to {2}..
|
||||
/// </summary>
|
||||
public static string BotTradeOfferResult {
|
||||
get {
|
||||
return ResourceManager.GetString("BotTradeOfferResult", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wyszukuje zlokalizowany ciąg podobny do ciągu Unable to login to Steam: {0}/{1}.
|
||||
/// </summary>
|
||||
|
||||
@@ -721,4 +721,6 @@
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC настройките са били променени!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -720,4 +720,6 @@ StackTrace:
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC nastavení bylo změněno!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -720,4 +720,6 @@ StackTrace:
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC konfiguration er blevet ændret!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -724,4 +724,6 @@ Prozesslaufzeit: {1}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Die IPC-Konfiguration wurde geändert!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -689,4 +689,6 @@ StackTrace:
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
|
||||
</root>
|
||||
@@ -723,4 +723,12 @@ Tiempo de actividad del proceso: {1}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>¡La configuración IPC ha sido cambiada!</value>
|
||||
</data>
|
||||
<data name="BotTradeOfferResult" xml:space="preserve">
|
||||
<value>La oferta de intercambio {0} se determina a ser {1} debido a {2}.</value>
|
||||
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
|
||||
</data>
|
||||
<data name="BotInvalidPasswordDuringLogin" xml:space="preserve">
|
||||
<value>Recibido el código de error InvalidPassword {0} veces seguidas. Es posible que la contraseña para esta cuenta sea incorrecta, ¡abortando!</value>
|
||||
<comment>{0} will be replaced by maximum allowed number of failed login attempts</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -714,4 +714,6 @@ StackTrace:
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC asetusta on muutettu!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -724,4 +724,6 @@ Durée de fonctionnement : {1}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>La configuration IPC a été modifiée !</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -639,6 +639,8 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -718,4 +718,6 @@ StackTrace: {2}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Az IPC konfig megváltozott!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -670,4 +670,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</root>
|
||||
@@ -718,4 +718,6 @@
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Configurazione IPC modificata!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -713,4 +713,6 @@
|
||||
</data>
|
||||
|
||||
|
||||
|
||||
|
||||
</root>
|
||||
@@ -720,4 +720,6 @@ StackTrace:
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC 환경설정이 변경되었습니다.</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -720,4 +720,6 @@ StackTrace:
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC konfigūracija buvo pakeista!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -723,4 +723,9 @@ Proces uptime: {1}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC-configuratie is gewijzigd!</value>
|
||||
</data>
|
||||
<data name="BotTradeOfferResult" xml:space="preserve">
|
||||
<value>Het ruilaanbod {0} is als {1} gemarkeerd vanwege {2}.</value>
|
||||
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
|
||||
</data>
|
||||
|
||||
</root>
|
||||
@@ -724,4 +724,12 @@ Czas procesu: {1}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Konfiguracja IPC została zmieniona!</value>
|
||||
</data>
|
||||
<data name="BotTradeOfferResult" xml:space="preserve">
|
||||
<value>Oferta wymiany {0} jest ustalona jako {1} z powodu {2}.</value>
|
||||
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
|
||||
</data>
|
||||
<data name="BotInvalidPasswordDuringLogin" xml:space="preserve">
|
||||
<value>Otrzymano kod błędu InvalidPassword {0} razy z rzędu. Twoje hasło do tego konta jest najprawdopodobniej błędne, przerywam!</value>
|
||||
<comment>{0} will be replaced by maximum allowed number of failed login attempts</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -724,4 +724,12 @@ Tempo de execução: {1}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>A configuração IPC foi alterada!</value>
|
||||
</data>
|
||||
<data name="BotTradeOfferResult" xml:space="preserve">
|
||||
<value>A oferta de troca {0} será determinada como {1} devido à {2}.</value>
|
||||
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
|
||||
</data>
|
||||
<data name="BotInvalidPasswordDuringLogin" xml:space="preserve">
|
||||
<value>O código de erro InvalidPassword foi recebido {0} vezes seguidas. A sua senha para essa conta provavelmente está errada, abortando!</value>
|
||||
<comment>{0} will be replaced by maximum allowed number of failed login attempts</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -554,4 +554,6 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</root>
|
||||
@@ -724,4 +724,12 @@ Process uptime: {1}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC config has been changed!</value>
|
||||
</data>
|
||||
<data name="BotTradeOfferResult" xml:space="preserve">
|
||||
<value>The trade offer {0} is determined to be {1} due to {2}.</value>
|
||||
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
|
||||
</data>
|
||||
<data name="BotInvalidPasswordDuringLogin" xml:space="preserve">
|
||||
<value>Received InvalidPassword error code {0} times in a row. Your password for this account is most likely wrong, aborting!</value>
|
||||
<comment>{0} will be replaced by maximum allowed number of failed login attempts</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -724,4 +724,6 @@ Proces: {1}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Configurația IPC a fost schimbată!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -724,4 +724,9 @@
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Конфигурация IPC была изменена!</value>
|
||||
</data>
|
||||
<data name="BotTradeOfferResult" xml:space="preserve">
|
||||
<value>По предложению обмена {0} принято решение {1} по причине {2}.</value>
|
||||
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
|
||||
</data>
|
||||
|
||||
</root>
|
||||
@@ -702,4 +702,6 @@ Interaktívna konzola je teraz aktívna, napíšte "c" pre vstup do príkazovéh
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Konfigurácia IPC bola zmenená!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -568,6 +568,8 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -621,6 +621,8 @@ StackTrace:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -724,4 +724,6 @@ Süreç çalışma zamanı: {1}</value>
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC yapılandırması değiştirildi!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -724,4 +724,9 @@
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Конфігурацію IPC було змінено!</value>
|
||||
</data>
|
||||
<data name="BotTradeOfferResult" xml:space="preserve">
|
||||
<value>Пропозицію обміну {0} вирішено {1} через {2}.</value>
|
||||
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
|
||||
</data>
|
||||
|
||||
</root>
|
||||
@@ -720,4 +720,6 @@ StackTrace:
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>Cấu hình IPC đã được thay đổi!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -724,4 +724,12 @@
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC 配置文件已被更改!</value>
|
||||
</data>
|
||||
<data name="BotTradeOfferResult" xml:space="preserve">
|
||||
<value>交易报价 {0} 被确定为 {1},原因是:{2}。</value>
|
||||
<comment>{0} will be replaced by trade offer ID (number), {1} will be replaced by internal ASF enum name, {2} will be replaced by technical reason why the trade was determined to be in this state</comment>
|
||||
</data>
|
||||
<data name="BotInvalidPasswordDuringLogin" xml:space="preserve">
|
||||
<value>连续收到无效密码(InvalidPassword)错误代码 {0} 次。您对此帐户的密码很可能是错误的,正在中止操作!</value>
|
||||
<comment>{0} will be replaced by maximum allowed number of failed login attempts</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -720,4 +720,6 @@
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC 設定檔已變更!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -723,4 +723,6 @@
|
||||
<data name="IPCConfigChanged" xml:space="preserve">
|
||||
<value>IPC 設定檔已變更!</value>
|
||||
</data>
|
||||
|
||||
|
||||
</root>
|
||||
@@ -180,7 +180,9 @@ namespace ArchiSteamFarm {
|
||||
|
||||
try {
|
||||
inventory = await Bot.ArchiWebHandler.GetInventoryAsync().Where(item => item.Tradable && acceptedMatchableTypes.Contains(item.Type)).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException) {
|
||||
} catch (HttpRequestException e) {
|
||||
Bot.ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
// This is actually inventory failure, so we'll stop sending heartbeats but not record it as valid check
|
||||
ShouldSendHeartBeats = false;
|
||||
|
||||
@@ -364,7 +366,9 @@ namespace ArchiSteamFarm {
|
||||
|
||||
try {
|
||||
ourInventory = await Bot.ArchiWebHandler.GetInventoryAsync().Where(item => acceptedMatchableTypes.Contains(item.Type)).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException) {
|
||||
} catch (HttpRequestException e) {
|
||||
Bot.ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
return (false, false);
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
@@ -432,7 +436,9 @@ namespace ArchiSteamFarm {
|
||||
|
||||
try {
|
||||
theirInventory = await Bot.ArchiWebHandler.GetInventoryAsync(listedUser.SteamID).Where(item => (!listedUser.MatchEverything || item.Tradable) && wantedSets.Contains((item.RealAppID, item.Type, item.Rarity)) && ((holdDuration.Value == 0) || !(((item.Type == Steam.Asset.EType.FoilTradingCard) || (item.Type == Steam.Asset.EType.TradingCard)) && CardsFarmer.SalesBlacklist.Contains(item.RealAppID)))).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException) {
|
||||
} catch (HttpRequestException e) {
|
||||
Bot.ArchiLogger.LogGenericWarningException(e);
|
||||
|
||||
continue;
|
||||
} catch (Exception e) {
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
|
||||
@@ -527,11 +527,15 @@ namespace ArchiSteamFarm {
|
||||
if (tradeOffer.OtherSteamID64 != 0) {
|
||||
// Always accept trades from SteamMasterID
|
||||
if (Bot.HasPermission(tradeOffer.OtherSteamID64, BotConfig.EPermission.Master)) {
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.Accepted, nameof(tradeOffer.OtherSteamID64) + " " + tradeOffer.OtherSteamID64 + ": " + BotConfig.EPermission.Master));
|
||||
|
||||
return ParseTradeResult.EResult.Accepted;
|
||||
}
|
||||
|
||||
// Always deny trades from blacklisted steamIDs
|
||||
if (Bot.IsBlacklistedFromTrades(tradeOffer.OtherSteamID64)) {
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.Blacklisted, nameof(tradeOffer.OtherSteamID64) + " " + tradeOffer.OtherSteamID64));
|
||||
|
||||
return ParseTradeResult.EResult.Blacklisted;
|
||||
}
|
||||
}
|
||||
@@ -540,6 +544,8 @@ namespace ArchiSteamFarm {
|
||||
switch (tradeOffer.ItemsToGive.Count) {
|
||||
case 0 when tradeOffer.ItemsToReceive.Count == 0:
|
||||
// If it's steam issue, try again later
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.TryAgain, nameof(tradeOffer.ItemsToReceive.Count) + " = 0"));
|
||||
|
||||
return ParseTradeResult.EResult.TryAgain;
|
||||
case 0:
|
||||
// Otherwise react accordingly, depending on our preference
|
||||
@@ -548,32 +554,46 @@ namespace ArchiSteamFarm {
|
||||
|
||||
// If we accept donations and bot trades, accept it right away
|
||||
if (acceptDonations && acceptBotTrades) {
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.Accepted, nameof(acceptDonations) + " = " + true + " && " + nameof(acceptBotTrades) + " = " + true));
|
||||
|
||||
return ParseTradeResult.EResult.Accepted;
|
||||
}
|
||||
|
||||
// If we don't accept donations, neither bot trades, deny it right away
|
||||
if (!acceptDonations && !acceptBotTrades) {
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.Rejected, nameof(acceptDonations) + " = " + false + " && " + nameof(acceptBotTrades) + " = " + false));
|
||||
|
||||
return ParseTradeResult.EResult.Rejected;
|
||||
}
|
||||
|
||||
// Otherwise we either accept donations but not bot trades, or we accept bot trades but not donations
|
||||
bool isBotTrade = (tradeOffer.OtherSteamID64 != 0) && Bot.Bots.Values.Any(bot => bot.SteamID == tradeOffer.OtherSteamID64);
|
||||
|
||||
return (acceptDonations && !isBotTrade) || (acceptBotTrades && isBotTrade) ? ParseTradeResult.EResult.Accepted : ParseTradeResult.EResult.Rejected;
|
||||
ParseTradeResult.EResult result = (acceptDonations && !isBotTrade) || (acceptBotTrades && isBotTrade) ? ParseTradeResult.EResult.Accepted : ParseTradeResult.EResult.Rejected;
|
||||
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, result, nameof(acceptDonations) + " = " + acceptDonations + " && " + nameof(acceptBotTrades) + " = " + acceptBotTrades + " && " + nameof(isBotTrade) + " = " + isBotTrade));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// If we don't have SteamTradeMatcher enabled, this is the end for us
|
||||
if (!Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.SteamTradeMatcher)) {
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.Rejected, nameof(BotConfig.ETradingPreferences.SteamTradeMatcher) + " = " + false));
|
||||
|
||||
return ParseTradeResult.EResult.Rejected;
|
||||
}
|
||||
|
||||
// Decline trade if we're giving more count-wise, this is a very naive pre-check, it'll be strengthened in more detailed fair types exchange next
|
||||
if (tradeOffer.ItemsToGive.Count > tradeOffer.ItemsToReceive.Count) {
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.Rejected, nameof(tradeOffer.ItemsToGive.Count) + ": " + tradeOffer.ItemsToGive.Count + " > " + tradeOffer.ItemsToReceive.Count));
|
||||
|
||||
return ParseTradeResult.EResult.Rejected;
|
||||
}
|
||||
|
||||
// Decline trade if we're requested to handle any not-accepted item type or if it's not fair games/types exchange
|
||||
if (!tradeOffer.IsValidSteamItemsRequest(Bot.BotConfig.MatchableTypes) || !IsFairExchange(tradeOffer.ItemsToGive, tradeOffer.ItemsToReceive)) {
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.Rejected, nameof(tradeOffer.IsValidSteamItemsRequest) + " || " + nameof(IsFairExchange)));
|
||||
|
||||
return ParseTradeResult.EResult.Rejected;
|
||||
}
|
||||
|
||||
@@ -584,6 +604,8 @@ namespace ArchiSteamFarm {
|
||||
|
||||
if (!holdDuration.HasValue) {
|
||||
// If we can't get trade hold duration, try again later
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.TryAgain, nameof(holdDuration)));
|
||||
|
||||
return ParseTradeResult.EResult.TryAgain;
|
||||
}
|
||||
|
||||
@@ -591,12 +613,16 @@ namespace ArchiSteamFarm {
|
||||
if (holdDuration.Value > 0) {
|
||||
// If trade hold duration exceeds our max, or user asks for cards with short lifespan, reject the trade
|
||||
if ((holdDuration.Value > ASF.GlobalConfig.MaxTradeHoldDuration) || tradeOffer.ItemsToGive.Any(item => ((item.Type == Steam.Asset.EType.FoilTradingCard) || (item.Type == Steam.Asset.EType.TradingCard)) && CardsFarmer.SalesBlacklist.Contains(item.RealAppID))) {
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.Rejected, nameof(holdDuration) + " > 0: " + holdDuration.Value));
|
||||
|
||||
return ParseTradeResult.EResult.Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're matching everything, this is enough for us
|
||||
if (Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything)) {
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.Accepted, BotConfig.ETradingPreferences.MatchEverything));
|
||||
|
||||
return ParseTradeResult.EResult.Accepted;
|
||||
}
|
||||
|
||||
@@ -612,12 +638,16 @@ namespace ArchiSteamFarm {
|
||||
|
||||
try {
|
||||
inventory = await Bot.ArchiWebHandler.GetInventoryAsync(Bot.SteamID).Where(item => wantedSets.Contains((item.RealAppID, item.Type, item.Rarity))).ToHashSetAsync().ConfigureAwait(false);
|
||||
} catch (HttpRequestException) {
|
||||
} catch (HttpRequestException e) {
|
||||
// If we can't check our inventory when not using MatchEverything, this is a temporary failure, try again later
|
||||
Bot.ArchiLogger.LogGenericWarningException(e);
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.TryAgain, nameof(inventory)));
|
||||
|
||||
return ParseTradeResult.EResult.TryAgain;
|
||||
} catch (Exception e) {
|
||||
// If we can't check our inventory when not using MatchEverything, this is a temporary failure, try again later
|
||||
Bot.ArchiLogger.LogGenericException(e);
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.TryAgain, nameof(inventory)));
|
||||
|
||||
return ParseTradeResult.EResult.TryAgain;
|
||||
}
|
||||
@@ -625,6 +655,7 @@ namespace ArchiSteamFarm {
|
||||
if (inventory.Count == 0) {
|
||||
// If we can't check our inventory when not using MatchEverything, this is a temporary failure, try again later
|
||||
Bot.ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorIsEmpty, nameof(inventory)));
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, ParseTradeResult.EResult.TryAgain, nameof(inventory)));
|
||||
|
||||
return ParseTradeResult.EResult.TryAgain;
|
||||
}
|
||||
@@ -632,7 +663,11 @@ namespace ArchiSteamFarm {
|
||||
bool accept = IsTradeNeutralOrBetter(inventory, tradeOffer.ItemsToGive.Select(item => item.CreateShallowCopy()).ToHashSet(), tradeOffer.ItemsToReceive.Select(item => item.CreateShallowCopy()).ToHashSet());
|
||||
|
||||
// We're now sure whether the trade is neutral+ for us or not
|
||||
return accept ? ParseTradeResult.EResult.Accepted : ParseTradeResult.EResult.Rejected;
|
||||
ParseTradeResult.EResult acceptResult = accept ? ParseTradeResult.EResult.Accepted : ParseTradeResult.EResult.Rejected;
|
||||
|
||||
Bot.ArchiLogger.LogGenericDebug(string.Format(Strings.BotTradeOfferResult, tradeOffer.TradeOfferID, acceptResult, nameof(IsTradeNeutralOrBetter)));
|
||||
|
||||
return acceptResult;
|
||||
}
|
||||
|
||||
public sealed class ParseTradeResult {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>4.2.3.8</Version>
|
||||
<Version>4.2.4.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
2
wiki
2
wiki
Submodule wiki updated: 424e0133fd...cf5d49a9de
Reference in New Issue
Block a user