From d479eb9f9755b74132afd1c56afd2a245f010196 Mon Sep 17 00:00:00 2001 From: Archi Date: Mon, 12 Jul 2021 21:45:17 +0200 Subject: [PATCH] Address Rider EAP inspections/cleanup --- ...eamFarm.CustomPlugins.ExamplePlugin.csproj | 30 +- .../CatAPI.cs | 2 +- ...iSteamFarm.CustomPlugins.PeriodicGC.csproj | 20 +- ...rm.OfficialPlugins.SteamTokenDumper.csproj | 58 +- .../Localization/Strings.Designer.cs | 2 +- .../Localization/Strings.resx | 392 ++--- .../SteamTokenDumperPlugin.cs | 10 +- .../ArchiSteamFarm.Tests.csproj | 24 +- ArchiSteamFarm.sln.DotSettings | 7 +- ArchiSteamFarm/ArchiSteamFarm.csproj | 154 +- ArchiSteamFarm/Core/ASF.cs | 11 +- ArchiSteamFarm/Core/Statistics.cs | 2 + .../Helpers/CrossProcessFileBasedSemaphore.cs | 8 +- ArchiSteamFarm/Helpers/SerializableFile.cs | 26 +- .../IPC/Controllers/Api/ASFController.cs | 4 +- .../IPC/Controllers/Api/BotController.cs | 8 +- .../IPC/Controllers/Api/CommandController.cs | 6 +- .../IPC/Controllers/Api/TypeController.cs | 5 + .../ApiAuthenticationMiddleware.cs | 2 +- .../IPC/Integration/EnumSchemaFilter.cs | 2 +- .../IPC/Responses/GenericResponse.cs | 1 + ArchiSteamFarm/IPC/Responses/TypeResponse.cs | 3 +- ArchiSteamFarm/Localization/Strings.resx | 1446 ++++++++--------- ArchiSteamFarm/NLog/ArchiLogger.cs | 27 +- ArchiSteamFarm/NLog/Logging.cs | 7 +- ArchiSteamFarm/NLog/Targets/SteamTarget.cs | 1 + ArchiSteamFarm/Program.cs | 10 +- ArchiSteamFarm/SharedInfo.cs | 1 + ArchiSteamFarm/Steam/Bot.cs | 24 +- .../Steam/Data/InventoryResponse.cs | 2 +- .../Steam/Integration/ArchiWebHandler.cs | 33 +- .../Steam/Integration/SteamChatMessage.cs | 1 + ArchiSteamFarm/Steam/Interaction/Actions.cs | 2 +- ArchiSteamFarm/Steam/Interaction/Commands.cs | 17 + .../Steam/Security/MobileAuthenticator.cs | 15 +- .../SteamKit2/InMemoryServerListProvider.cs | 2 +- ArchiSteamFarm/Steam/Storage/BotConfig.cs | 2 + ArchiSteamFarm/Storage/GlobalConfig.cs | 1 + ArchiSteamFarm/TrimmerRoots.xml | 10 +- ArchiSteamFarm/overlay/all/Changelog.html | 2 +- .../overlay/all/ConfigGenerator.html | 2 +- ArchiSteamFarm/overlay/all/Manual.html | 2 +- ArchiSteamFarm/overlay/all/UI.html | 2 +- Directory.Build.props | 102 +- 44 files changed, 1251 insertions(+), 1237 deletions(-) diff --git a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj index c2baab487..678906514 100644 --- a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj +++ b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/ArchiSteamFarm.CustomPlugins.ExamplePlugin.csproj @@ -1,20 +1,20 @@ - - Library - + + Library + - - - - - - + + + + + + - - - + + + - - - + + + diff --git a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatAPI.cs b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatAPI.cs index 2fd3fec1d..daf4444df 100644 --- a/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatAPI.cs +++ b/ArchiSteamFarm.CustomPlugins.ExamplePlugin/CatAPI.cs @@ -50,7 +50,7 @@ namespace ArchiSteamFarm.CustomPlugins.ExamplePlugin { throw new InvalidOperationException(nameof(response.Content.Link)); } - return Uri.EscapeUriString(response.Content!.Link!); + return Uri.EscapeUriString(response.Content.Link); } #pragma warning disable CA1812 // False positive, the class is used during json deserialization diff --git a/ArchiSteamFarm.CustomPlugins.PeriodicGC/ArchiSteamFarm.CustomPlugins.PeriodicGC.csproj b/ArchiSteamFarm.CustomPlugins.PeriodicGC/ArchiSteamFarm.CustomPlugins.PeriodicGC.csproj index 4ba9354d5..3788f8b1d 100644 --- a/ArchiSteamFarm.CustomPlugins.PeriodicGC/ArchiSteamFarm.CustomPlugins.PeriodicGC.csproj +++ b/ArchiSteamFarm.CustomPlugins.PeriodicGC/ArchiSteamFarm.CustomPlugins.PeriodicGC.csproj @@ -1,14 +1,14 @@ - - Library - + + Library + - - - - + + + + - - - + + + diff --git a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.csproj b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.csproj index 191d43dca..0ac7cdf8c 100644 --- a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.csproj +++ b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper.csproj @@ -1,36 +1,36 @@ - - Library - + + Library + - - - - - - - + + + + + + + - - - + + + - - - + + + - - - ResXFileCodeGenerator - Strings.Designer.cs - - + + + ResXFileCodeGenerator + Strings.Designer.cs + + - - - True - Strings.resx - True - - + + + True + Strings.resx + True + + diff --git a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.Designer.cs b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.Designer.cs index 23508cf2b..1c8f33367 100644 --- a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.Designer.cs +++ b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 diff --git a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.resx b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.resx index c7467c206..0172ad559 100644 --- a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.resx +++ b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/Localization/Strings.resx @@ -1,226 +1,172 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 - - - {0} has been disabled due to a missing build token - {0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin") - - - {0} is currently disabled according to your configuration. If you'd like to help SteamDB in data submission, please check out our wiki. - {0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin") - - - {0} has been initialized successfully, thank you in advance for your help. The first submission will happen in approximately {1} from now. - {0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes") - - - {0} could not be loaded, a fresh instance will be initialized... - {0} will be replaced by the name of the file (e.g. "GlobalCache") - - - There are no apps that require a refresh on this bot instance. - - - Retrieving a total of {0} app access tokens... - {0} will be replaced by the number (total count) of app access tokens being retrieved - - - Retrieving {0} app access tokens... - {0} will be replaced by the number (count this batch) of app access tokens being retrieved - - - Finished retrieving {0} app access tokens. - {0} will be replaced by the number (count this batch) of app access tokens retrieved - - - Finished retrieving a total of {0} app access tokens. - {0} will be replaced by the number (total count) of app access tokens retrieved - - - Retrieving all depots for a total of {0} apps... - {0} will be replaced by the number (total count) of apps being retrieved - - - Retrieving {0} app infos... - {0} will be replaced by the number (count this batch) of app infos being retrieved - - - Finished retrieving {0} app infos. - {0} will be replaced by the number (count this batch) of app infos retrieved - - - Retrieving {0} depot keys... - {0} will be replaced by the number (count this batch) of depot keys being retrieved - - - Finished retrieving {0} depot keys. - {0} will be replaced by the number (count this batch) of depot keys retrieved - - - Finished retrieving all depot keys for a total of {0} apps. - {0} will be replaced by the number (total count) of apps retrieved - - - There is no new data to submit, everything is up-to-date. - - - Could not submit the data because there is no valid SteamID set that we could classify as a contributor. Consider setting up {0} property. - {0} will be replaced by the name of the config property (e.g. "SteamOwnerID") that the user is expected to set - - - Submitting a total of registered apps/packages/depots: {0}/{1}/{2}... - {0} will be replaced by the number of app access tokens being submitted, {1} will be replaced by the number of package access tokens being submitted, {2} will be replaced by the number of depot keys being submitted - - - The submission has failed due to too many requests sent, we'll try again in approximately {0} from now. - {0} will be replaced by translated TimeSpan string (such as "53 minutes") - - - The data has been successfully submitted. The server has registered a total of new apps/packages/depots: {0} ({1} verified)/{2} ({3} verified)/{4} ({5} verified). - {0} will be replaced by the number of new app access tokens that the server has registered, {1} will be replaced by the number of verified app access tokens that the server has registered, {2} will be replaced by the number of new package access tokens that the server has registered, {3} will be replaced by the number of verified package access tokens that the server has registered, {4} will be replaced by the number of new depot keys that the server has registered, {5} will be replaced by the number of verified depot keys that the server has registered - - - New apps: {0} - {0} will be replaced by list of the apps (IDs, numbers), separated by a comma - - - Verified apps: {0} - {0} will be replaced by list of the apps (IDs, numbers), separated by a comma - - - New packages: {0} - {0} will be replaced by list of the packages (IDs, numbers), separated by a comma - - - Verified packages: {0} - {0} will be replaced by list of the packages (IDs, numbers), separated by a comma - - - New depots: {0} - {0} will be replaced by list of the depots (IDs, numbers), separated by a comma - - - Verified depots: {0} - {0} will be replaced by list of the depots (IDs, numbers), separated by a comma - - - {0} initialized, the plugin will not resolve any of those: {1}. - {0} will be replaced by the name of the config property (e.g. "SecretPackageIDs"), {1} will be replaced by list of the objects (IDs, numbers), separated by a comma - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + {0} has been disabled due to a missing build token + {0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin") + + + {0} is currently disabled according to your configuration. If you'd like to help SteamDB in data submission, please check out our wiki. + {0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin") + + + {0} has been initialized successfully, thank you in advance for your help. The first submission will happen in approximately {1} from now. + {0} will be replaced by the name of the plugin (e.g. "SteamTokenDumperPlugin"), {1} will be replaced by translated TimeSpan string (such as "53 minutes") + + + {0} could not be loaded, a fresh instance will be initialized... + {0} will be replaced by the name of the file (e.g. "GlobalCache") + + + There are no apps that require a refresh on this bot instance. + + + Retrieving a total of {0} app access tokens... + {0} will be replaced by the number (total count) of app access tokens being retrieved + + + Retrieving {0} app access tokens... + {0} will be replaced by the number (count this batch) of app access tokens being retrieved + + + Finished retrieving {0} app access tokens. + {0} will be replaced by the number (count this batch) of app access tokens retrieved + + + Finished retrieving a total of {0} app access tokens. + {0} will be replaced by the number (total count) of app access tokens retrieved + + + Retrieving all depots for a total of {0} apps... + {0} will be replaced by the number (total count) of apps being retrieved + + + Retrieving {0} app infos... + {0} will be replaced by the number (count this batch) of app infos being retrieved + + + Finished retrieving {0} app infos. + {0} will be replaced by the number (count this batch) of app infos retrieved + + + Retrieving {0} depot keys... + {0} will be replaced by the number (count this batch) of depot keys being retrieved + + + Finished retrieving {0} depot keys. + {0} will be replaced by the number (count this batch) of depot keys retrieved + + + Finished retrieving all depot keys for a total of {0} apps. + {0} will be replaced by the number (total count) of apps retrieved + + + There is no new data to submit, everything is up-to-date. + + + Could not submit the data because there is no valid SteamID set that we could classify as a contributor. Consider setting up {0} property. + {0} will be replaced by the name of the config property (e.g. "SteamOwnerID") that the user is expected to set + + + Submitting a total of registered apps/packages/depots: {0}/{1}/{2}... + {0} will be replaced by the number of app access tokens being submitted, {1} will be replaced by the number of package access tokens being submitted, {2} will be replaced by the number of depot keys being submitted + + + The submission has failed due to too many requests sent, we'll try again in approximately {0} from now. + {0} will be replaced by translated TimeSpan string (such as "53 minutes") + + + The data has been successfully submitted. The server has registered a total of new apps/packages/depots: {0} ({1} verified)/{2} ({3} verified)/{4} ({5} verified). + {0} will be replaced by the number of new app access tokens that the server has registered, {1} will be replaced by the number of verified app access tokens that the server has registered, {2} will be replaced by the number of new package access tokens that the server has registered, {3} will be replaced by the number of verified package access tokens that the server has registered, {4} will be replaced by the number of new depot keys that the server has registered, {5} will be replaced by the number of verified depot keys that the server has registered + + + New apps: {0} + {0} will be replaced by list of the apps (IDs, numbers), separated by a comma + + + Verified apps: {0} + {0} will be replaced by list of the apps (IDs, numbers), separated by a comma + + + New packages: {0} + {0} will be replaced by list of the packages (IDs, numbers), separated by a comma + + + Verified packages: {0} + {0} will be replaced by list of the packages (IDs, numbers), separated by a comma + + + New depots: {0} + {0} will be replaced by list of the depots (IDs, numbers), separated by a comma + + + Verified depots: {0} + {0} will be replaced by list of the depots (IDs, numbers), separated by a comma + + + {0} initialized, the plugin will not resolve any of those: {1}. + {0} will be replaced by the name of the config property (e.g. "SecretPackageIDs"), {1} will be replaced by list of the objects (IDs, numbers), separated by a comma + diff --git a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SteamTokenDumperPlugin.cs b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SteamTokenDumperPlugin.cs index 32569f8d1..3dd8a84cb 100644 --- a/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SteamTokenDumperPlugin.cs +++ b/ArchiSteamFarm.OfficialPlugins.SteamTokenDumper/SteamTokenDumperPlugin.cs @@ -169,7 +169,7 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper { } SemaphoreSlim refreshSemaphore = new(1, 1); - Timer refreshTimer = new(async _ => await Refresh(bot).ConfigureAwait(false)); + Timer refreshTimer = new(OnBotRefreshTimer, bot, Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan); if (!BotSynchronizations.TryAdd(bot, (refreshSemaphore, refreshTimer))) { refreshSemaphore.Dispose(); @@ -246,6 +246,14 @@ namespace ArchiSteamFarm.OfficialPlugins.SteamTokenDumper { GlobalCache.OnPICSChangesRestart(currentChangeNumber); } + private static async void OnBotRefreshTimer(object? state) { + if (state is not Bot bot) { + throw new InvalidOperationException(nameof(state)); + } + + await Refresh(bot).ConfigureAwait(false); + } + private static async void OnLicenseList(Bot bot, SteamApps.LicenseListCallback callback) { if (bot == null) { throw new ArgumentNullException(nameof(bot)); diff --git a/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj b/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj index fa1d15db2..8cc74480c 100644 --- a/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj +++ b/ArchiSteamFarm.Tests/ArchiSteamFarm.Tests.csproj @@ -1,16 +1,16 @@ - - Library - + + Library + - - - - - - + + + + + + - - - + + + diff --git a/ArchiSteamFarm.sln.DotSettings b/ArchiSteamFarm.sln.DotSettings index cee0334a8..7a923145a 100644 --- a/ArchiSteamFarm.sln.DotSettings +++ b/ArchiSteamFarm.sln.DotSettings @@ -1,4 +1,4 @@ - + True True FullFormat @@ -41,6 +41,7 @@ SUGGESTION SUGGESTION SUGGESTION + HINT WARNING WARNING WARNING @@ -221,10 +222,12 @@ WARNING WARNING WARNING + SUGGESTION WARNING WARNING WARNING HINT + HINT WARNING SUGGESTION SUGGESTION @@ -269,6 +272,7 @@ SUGGESTION WARNING SUGGESTION + SUGGESTION SUGGESTION SUGGESTION SUGGESTION @@ -285,6 +289,7 @@ SUGGESTION SUGGESTION SUGGESTION + SUGGESTION SUGGESTION SUGGESTION SUGGESTION diff --git a/ArchiSteamFarm/ArchiSteamFarm.csproj b/ArchiSteamFarm/ArchiSteamFarm.csproj index d01f19160..fdca8ca16 100644 --- a/ArchiSteamFarm/ArchiSteamFarm.csproj +++ b/ArchiSteamFarm/ArchiSteamFarm.csproj @@ -1,87 +1,87 @@ - - $(DefaultItemExcludes);config/**;debug/**;logs/**;overlay/** - true - false - Exe - + + $(DefaultItemExcludes);config/**;debug/**;logs/**;overlay/** + true + false + Exe + - - true - + + true + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - + + + - - - PublicResXFileCodeGenerator - Strings.Designer.cs - - + + + PublicResXFileCodeGenerator + Strings.Designer.cs + + - - - True - Strings.resx - True - - + + + True + Strings.resx + True + + - - - PreserveNewest - true - %(RecursiveDir)%(Filename)%(Extension) - - - PreserveNewest - true - %(RecursiveDir)%(Filename)%(Extension) - - - PreserveNewest - www\%(RecursiveDir)%(Filename)%(Extension) - - + + + PreserveNewest + true + %(RecursiveDir)%(Filename)%(Extension) + + + PreserveNewest + true + %(RecursiveDir)%(Filename)%(Extension) + + + PreserveNewest + www\%(RecursiveDir)%(Filename)%(Extension) + + diff --git a/ArchiSteamFarm/Core/ASF.cs b/ArchiSteamFarm/Core/ASF.cs index b9a1346da..07689adbc 100644 --- a/ArchiSteamFarm/Core/ASF.cs +++ b/ArchiSteamFarm/Core/ASF.cs @@ -231,7 +231,7 @@ namespace ArchiSteamFarm.Core { return null; } - Version newVersion = new(releaseResponse.Tag!); + Version newVersion = new(releaseResponse.Tag); ArchiLogger.LogGenericInfo(string.Format(CultureInfo.CurrentCulture, Strings.UpdateVersionInfo, SharedInfo.Version, newVersion)); @@ -400,6 +400,7 @@ namespace ArchiSteamFarm.Core { if (!string.IsNullOrEmpty(Program.NetworkGroup)) { using SHA256 hashingAlgorithm = SHA256.Create(); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework networkGroupText = "-" + BitConverter.ToString(hashingAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(Program.NetworkGroup!))).Replace("-", "", StringComparison.Ordinal); } else if (!string.IsNullOrEmpty(GlobalConfig.WebProxyText)) { using SHA256 hashingAlgorithm = SHA256.Create(); @@ -429,6 +430,8 @@ namespace ArchiSteamFarm.Core { if (loadedAssembliesNames == null) { Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework loadedAssembliesNames = loadedAssemblies.Select(loadedAssembly => loadedAssembly.FullName).Where(name => !string.IsNullOrEmpty(name)).ToHashSet()!; } @@ -439,6 +442,8 @@ namespace ArchiSteamFarm.Core { } } + private static async void OnAutoUpdatesTimer(object? state) => await UpdateAndRestart().ConfigureAwait(false); + private static async void OnChanged(object sender, FileSystemEventArgs e) { if (sender == null) { throw new ArgumentNullException(nameof(sender)); @@ -882,7 +887,7 @@ namespace ArchiSteamFarm.Core { TimeSpan autoUpdatePeriod = TimeSpan.FromHours(GlobalConfig.UpdatePeriod); AutoUpdatesTimer = new Timer( - async _ => await UpdateAndRestart().ConfigureAwait(false), + OnAutoUpdatesTimer, null, autoUpdatePeriod, // Delay autoUpdatePeriod // Period @@ -1016,7 +1021,7 @@ namespace ArchiSteamFarm.Core { } if (!Directory.Exists(directory)) { - Directory.CreateDirectory(directory!); + Directory.CreateDirectory(directory); } // We're not interested in extracting placeholder files (but we still want directories created for them, done above) diff --git a/ArchiSteamFarm/Core/Statistics.cs b/ArchiSteamFarm/Core/Statistics.cs index e6d1993c0..7045b88eb 100644 --- a/ArchiSteamFarm/Core/Statistics.cs +++ b/ArchiSteamFarm/Core/Statistics.cs @@ -228,6 +228,8 @@ namespace ArchiSteamFarm.Core { { "MatchEverything", Bot.BotConfig.TradingPreferences.HasFlag(BotConfig.ETradingPreferences.MatchEverything) ? "1" : "0" }, { "Nickname", nickname ?? "" }, { "SteamID", Bot.SteamID.ToString(CultureInfo.InvariantCulture) }, + + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework { "TradeToken", tradeToken! } }; diff --git a/ArchiSteamFarm/Helpers/CrossProcessFileBasedSemaphore.cs b/ArchiSteamFarm/Helpers/CrossProcessFileBasedSemaphore.cs index 7b239fcbd..bd43f4396 100644 --- a/ArchiSteamFarm/Helpers/CrossProcessFileBasedSemaphore.cs +++ b/ArchiSteamFarm/Helpers/CrossProcessFileBasedSemaphore.cs @@ -161,13 +161,13 @@ namespace ArchiSteamFarm.Helpers { } if (!Directory.Exists(directoryPath)) { - Directory.CreateDirectory(directoryPath!); + Directory.CreateDirectory(directoryPath); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - DirectoryInfo directoryInfo = new(directoryPath!); + DirectoryInfo directoryInfo = new(directoryPath); try { - DirectorySecurity directorySecurity = new(directoryPath!, AccessControlSections.All); + DirectorySecurity directorySecurity = new(directoryPath, AccessControlSections.All); directoryInfo.SetAccessControl(directorySecurity); } catch (PrivilegeNotHeldException e) { @@ -179,7 +179,7 @@ namespace ArchiSteamFarm.Helpers { #else } else if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { #endif - OS.UnixSetFileAccess(directoryPath!, OS.EUnixPermission.Combined777); + OS.UnixSetFileAccess(directoryPath, OS.EUnixPermission.Combined777); } } diff --git a/ArchiSteamFarm/Helpers/SerializableFile.cs b/ArchiSteamFarm/Helpers/SerializableFile.cs index 82d9c189f..e72a093ec 100644 --- a/ArchiSteamFarm/Helpers/SerializableFile.cs +++ b/ArchiSteamFarm/Helpers/SerializableFile.cs @@ -20,9 +20,9 @@ // limitations under the License. using System; +using System.IO; using System.Threading; using System.Threading.Tasks; -using ArchiSteamFarm.Compatibility; using ArchiSteamFarm.Core; using Newtonsoft.Json; @@ -85,20 +85,20 @@ namespace ArchiSteamFarm.Helpers { // We always want to write entire content to temporary file first, in order to never load corrupted data, also when target file doesn't exist string newFilePath = FilePath + ".new"; - if (System.IO.File.Exists(FilePath)) { - string currentJson = await File.ReadAllTextAsync(FilePath!).ConfigureAwait(false); + if (File.Exists(FilePath)) { + string currentJson = await Compatibility.File.ReadAllTextAsync(FilePath!).ConfigureAwait(false); if (json == currentJson) { return; } - await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); + await Compatibility.File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); - System.IO.File.Replace(newFilePath, FilePath, null); + File.Replace(newFilePath, FilePath!, null); } else { - await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); + await Compatibility.File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); - System.IO.File.Move(newFilePath, FilePath); + File.Move(newFilePath, FilePath!); } } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); @@ -140,20 +140,20 @@ namespace ArchiSteamFarm.Helpers { try { // We always want to write entire content to temporary file first, in order to never load corrupted data, also when target file doesn't exist - if (System.IO.File.Exists(filePath)) { - string currentJson = await File.ReadAllTextAsync(filePath).ConfigureAwait(false); + if (File.Exists(filePath)) { + string currentJson = await Compatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false); if (json == currentJson) { return true; } - await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); + await Compatibility.File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); - System.IO.File.Replace(newFilePath, filePath, null); + File.Replace(newFilePath, filePath, null); } else { - await File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); + await Compatibility.File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false); - System.IO.File.Move(newFilePath, filePath); + File.Move(newFilePath, filePath); } return true; diff --git a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs index 0ea13ec33..6d8b4835f 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/ASFController.cs @@ -54,7 +54,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(request.StringToEncrypt)))); } - string? encryptedString = Actions.Encrypt(request.CryptoMethod, request.StringToEncrypt!); + string? encryptedString = Actions.Encrypt(request.CryptoMethod, request.StringToEncrypt); return Ok(new GenericResponse(encryptedString)); } @@ -92,7 +92,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(request.StringToHash)))); } - string hash = Actions.Hash(request.HashingMethod, request.StringToHash!); + string hash = Actions.Hash(request.HashingMethod, request.StringToHash); return Ok(new GenericResponse(hash)); } diff --git a/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs b/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs index a955c3feb..ec0d55bb3 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/BotController.cs @@ -82,7 +82,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(bots)))); } - return Ok(new GenericResponse>(bots.Where(bot => !string.IsNullOrEmpty(bot.BotName)).ToDictionary(bot => bot.BotName, bot => bot, Bot.BotsComparer)!)); + return Ok(new GenericResponse>(bots.Where(bot => !string.IsNullOrEmpty(bot.BotName)).ToDictionary(bot => bot.BotName, bot => bot, Bot.BotsComparer))); } /// @@ -280,7 +280,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botNames))); } - IList results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.SetUserInput(request.Type, request.Value!)))).ConfigureAwait(false); + IList results = await Utilities.InParallel(bots.Select(bot => Task.Run(() => bot.SetUserInput(request.Type, request.Value)))).ConfigureAwait(false); return Ok(results.All(result => result) ? new GenericResponse(true) : new GenericResponse(false, Strings.WarningFailed)); } @@ -380,7 +380,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { throw new InvalidOperationException(nameof(Bot.Bots)); } - if (string.IsNullOrEmpty(request.NewName) || !ASF.IsValidBotName(request.NewName!) || Bot.Bots.ContainsKey(request.NewName!)) { + if (string.IsNullOrEmpty(request.NewName) || !ASF.IsValidBotName(request.NewName) || Bot.Bots.ContainsKey(request.NewName)) { return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(request.NewName)))); } @@ -388,7 +388,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.BotNotFound, botName))); } - bool result = await bot.Rename(request.NewName!).ConfigureAwait(false); + bool result = await bot.Rename(request.NewName).ConfigureAwait(false); return Ok(new GenericResponse(result)); } diff --git a/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs b/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs index 88e424e3f..e8cc0cd00 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/CommandController.cs @@ -67,16 +67,18 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { return BadRequest(new GenericResponse(false, Strings.ErrorNoBotsDefined)); } - string command = request.Command!; + string command = request.Command; string? commandPrefix = ASF.GlobalConfig != null ? ASF.GlobalConfig.CommandPrefix : GlobalConfig.DefaultCommandPrefix; + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (!string.IsNullOrEmpty(commandPrefix) && command.StartsWith(commandPrefix!, StringComparison.Ordinal)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (command.Length == commandPrefix!.Length) { // If the message starts with command prefix and is of the same length as command prefix, then it's just empty command trigger, useless return BadRequest(new GenericResponse(false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(command)))); } - command = command[commandPrefix!.Length..]; + command = command[commandPrefix.Length..]; } string? response = await targetBot.Commands.Response(steamOwnerID, command).ConfigureAwait(false); diff --git a/ArchiSteamFarm/IPC/Controllers/Api/TypeController.cs b/ArchiSteamFarm/IPC/Controllers/Api/TypeController.cs index 54d59788f..eaf6d5ca7 100644 --- a/ArchiSteamFarm/IPC/Controllers/Api/TypeController.cs +++ b/ArchiSteamFarm/IPC/Controllers/Api/TypeController.cs @@ -68,6 +68,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { string? unifiedName = field.FieldType.GetUnifiedName(); if (!string.IsNullOrEmpty(unifiedName)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework body[jsonProperty.PropertyName ?? field.Name] = unifiedName!; } } @@ -80,6 +81,7 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { string? unifiedName = property.PropertyType.GetUnifiedName(); if (!string.IsNullOrEmpty(unifiedName)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework body[jsonProperty.PropertyName ?? property.Name] = unifiedName!; } } @@ -103,7 +105,10 @@ namespace ArchiSteamFarm.IPC.Controllers.Api { continue; } + // ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework body[valueText!] = valueObjText!; + + // ReSharper restore RedundantSuppressNullableWarningExpression - required for .NET Framework } } diff --git a/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs b/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs index 205e898ac..19d77d5e6 100644 --- a/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs +++ b/ArchiSteamFarm/IPC/Integration/ApiAuthenticationMiddleware.cs @@ -142,7 +142,7 @@ namespace ArchiSteamFarm.IPC.Integration { ArchiCryptoHelper.EHashingMethod ipcPasswordFormat = ASF.GlobalConfig != null ? ASF.GlobalConfig.IPCPasswordFormat : GlobalConfig.DefaultIPCPasswordFormat; - string inputHash = ArchiCryptoHelper.Hash(ipcPasswordFormat, inputPassword!); + string inputHash = ArchiCryptoHelper.Hash(ipcPasswordFormat, inputPassword); bool authorized = ipcPassword == inputHash; diff --git a/ArchiSteamFarm/IPC/Integration/EnumSchemaFilter.cs b/ArchiSteamFarm/IPC/Integration/EnumSchemaFilter.cs index d753567b9..e22f40b13 100644 --- a/ArchiSteamFarm/IPC/Integration/EnumSchemaFilter.cs +++ b/ArchiSteamFarm/IPC/Integration/EnumSchemaFilter.cs @@ -78,7 +78,7 @@ namespace ArchiSteamFarm.IPC.Integration { throw new InvalidOperationException(nameof(enumValue)); } - definition.Add(enumName!, enumObject); + definition.Add(enumName, enumObject); } schema.AddExtension("x-definition", definition); diff --git a/ArchiSteamFarm/IPC/Responses/GenericResponse.cs b/ArchiSteamFarm/IPC/Responses/GenericResponse.cs index c99679e95..094f5205f 100644 --- a/ArchiSteamFarm/IPC/Responses/GenericResponse.cs +++ b/ArchiSteamFarm/IPC/Responses/GenericResponse.cs @@ -60,6 +60,7 @@ namespace ArchiSteamFarm.IPC.Responses { public GenericResponse(bool success, string? message = null) { Success = success; + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework Message = !string.IsNullOrEmpty(message) ? message! : success ? "OK" : Strings.WarningFailed; } } diff --git a/ArchiSteamFarm/IPC/Responses/TypeResponse.cs b/ArchiSteamFarm/IPC/Responses/TypeResponse.cs index 6cdf12396..ceeb68736 100644 --- a/ArchiSteamFarm/IPC/Responses/TypeResponse.cs +++ b/ArchiSteamFarm/IPC/Responses/TypeResponse.cs @@ -22,7 +22,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using JetBrains.Annotations; using Newtonsoft.Json; namespace ArchiSteamFarm.IPC.Responses { @@ -46,7 +45,7 @@ namespace ArchiSteamFarm.IPC.Responses { [Required] public TypeProperties Properties { get; private set; } - internal TypeResponse([NotNull] Dictionary body, [NotNull] TypeProperties properties) { + internal TypeResponse(Dictionary body, TypeProperties properties) { Body = body ?? throw new ArgumentNullException(nameof(body)); Properties = properties ?? throw new ArgumentNullException(nameof(properties)); } diff --git a/ArchiSteamFarm/Localization/Strings.resx b/ArchiSteamFarm/Localization/Strings.resx index 9657adb86..aaccd3c7f 100644 --- a/ArchiSteamFarm/Localization/Strings.resx +++ b/ArchiSteamFarm/Localization/Strings.resx @@ -1,757 +1,703 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 - - - Accepting trade: {0} - {0} will be replaced by trade number - - - ASF will automatically check for new versions every {0}. - {0} will be replaced by translated TimeSpan string (such as "24 hours") - - - Content: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + Accepting trade: {0} + {0} will be replaced by trade number + + + ASF will automatically check for new versions every {0}. + {0} will be replaced by translated TimeSpan string (such as "24 hours") + + + Content: {0} - {0} will be replaced by content string. Please note that this string should include newline for formatting. - - - Configured {0} property is invalid: {1} - {0} will be replaced by name of the configuration property, {1} will be replaced by invalid value - - - ASF V{0} has run into fatal exception before core logging module was even able to initialize! - {0} will be replaced by version number - - - Exception: {0}() {1} + {0} will be replaced by content string. Please note that this string should include newline for formatting. + + + Configured {0} property is invalid: {1} + {0} will be replaced by name of the configuration property, {1} will be replaced by invalid value + + + ASF V{0} has run into fatal exception before core logging module was even able to initialize! + {0} will be replaced by version number + + + Exception: {0}() {1} StackTrace: {2} - {0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting. - - - Exiting with nonzero error code! - - - Request failing: {0} - {0} will be replaced by URL of the request - - - 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. - {0} will be replaced by file's path - - - {0} is invalid! - {0} will be replaced by object's name - - - No bots are defined. Did you forget to configure your ASF? - - - {0} is null! - {0} will be replaced by object's name - - - Parsing {0} failed! - {0} will be replaced by object's name - - - Request failed after {0} attempts! - {0} will be replaced by maximum number of tries - - - Could not check latest version! - - - Could not proceed with update because there is no asset that relates to currently running version! Automatic update to that version is not possible. - - - Could not proceed with an update because that version doesn't include any assets! - - - Received a request for user input, but process is running in headless mode! - - - Exiting... - - - Failed! - - - Global config file has been changed! - - - Global config file has been removed! - - - Ignoring trade: {0} - {0} will be replaced by trade number - - - Logging in to {0}... - {0} will be replaced by service's name - - - No bots are running, exiting... - - - Refreshing our session! - - - Rejecting trade: {0} - {0} will be replaced by trade number - - - Restarting... - - - Starting... - - - Success! - - - Unlocking parental account... - - - Checking for new version... - - - Downloading new version: {0} ({1} MB)... While waiting, consider donating if you appreciate the work being done! :) - {0} will be replaced by version string, {1} will be replaced by update size (in megabytes) - - - Update process finished! - - - New ASF version is available! Consider updating yourself! - - - Local version: {0} | Remote version: {1} - {0} will be replaced by current version, {1} will be replaced by remote version - - - Please enter your 2FA code from your Steam authenticator app: - Please note that this translation should end with space - - - Please enter SteamGuard auth code that was sent on your e-mail: - Please note that this translation should end with space - - - Please enter your Steam login: - Please note that this translation should end with space - - - Please enter Steam parental code: - Please note that this translation should end with space - - - Please enter your Steam password: - Please note that this translation should end with space - - - Received unknown value for {0}, please report this: {1} - {0} will be replaced by object's name, {1} will be replaced by value for that object - - - IPC server ready! - - - Starting IPC server... - - - This bot has already stopped! - - - Couldn't find any bot named {0}! - {0} will be replaced by bot's name query (string) - - - There are {0}/{1} bots running, with total of {2} games ({3} cards) left to farm. - {0} will be replaced by number of active bots, {1} will be replaced by total number of bots, {2} will be replaced by total number of games left to farm, {3} will be replaced by total number of cards left to farm - - - Bot is farming game: {0} ({1}, {2} card drops remaining) from a total of {3} games ({4} cards) left to farm (~{5} remaining). - {0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm, {3} will be replaced by total number of games to farm, {4} will be replaced by total number of cards to farm, {5} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes") - - - Bot is farming games: {0} from a total of {1} games ({2} cards) left to farm (~{3} remaining). - {0} will be replaced by list of the games (IDs, numbers), {1} will be replaced by total number of games to farm, {2} will be replaced by total number of cards to farm, {3} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes") - - - Checking first badge page... - - - Checking other badge pages... - - - Chosen farming algorithm: {0} - {0} will be replaced by the name of chosen farming algorithm - - - Done! - - - We have a total of {0} games ({1} cards) left to farm (~{2} remaining)... - {0} will be replaced by number of games, {1} will be replaced by number of cards, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes") - - - Farming finished! - - - Finished farming: {0} ({1}) after {2} of playtime! - {0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes") - - - Finished farming games: {0} - {0} will be replaced by list of the games (IDs, numbers), separated by a comma - - - Farming status for {0} ({1}): {2} cards remaining - {0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm - - - Farming stopped! - - - Ignoring this request, as permanent pause is enabled! - - - We don't have anything to farm on this account! - - - Now farming: {0} ({1}) - {0} will be replaced by game's ID (number), {1} will be replaced by game's name - - - Now farming: {0} - {0} will be replaced by list of the games (IDs, numbers), separated by a comma - - - Playing is currently unavailable, we'll try again later! - - - Still farming: {0} ({1}) - {0} will be replaced by game's ID (number), {1} will be replaced by game's name - - - Still farming: {0} - {0} will be replaced by list of the games (IDs, numbers), separated by a comma - - - Stopped farming: {0} ({1}) - {0} will be replaced by game's ID (number), {1} will be replaced by game's name - - - Stopped farming: {0} - {0} will be replaced by list of the games (IDs, numbers), separated by a comma - - - Unknown command! - - - Could not get badges' information, we will try again later! - - - Could not check cards status for: {0} ({1}), we will try again later! - {0} will be replaced by game's ID (number), {1} will be replaced by game's name - - - Accepting gift: {0}... - {0} will be replaced by giftID (number) - - - This account is limited, farming process is unavailable until the restriction is removed! - - - ID: {0} | Status: {1} - {0} will be replaced by game's ID (number), {1} will be replaced by status string - - - ID: {0} | Status: {1} | Items: {2} - {0} will be replaced by game's ID (number), {1} will be replaced by status string, {2} will be replaced by list of granted IDs (numbers), separated by a comma - - - This bot is already running! - - - Converting .maFile into ASF format... - - - Successfully finished importing mobile authenticator! - - - 2FA Token: {0} - {0} will be replaced by generated 2FA token (string) - - - Automatic farming has paused! - - - Automatic farming has resumed! - - - Automatic farming is paused already! - - - Automatic farming is resumed already! - - - Connected to Steam! - - - Disconnected from Steam! - - - Disconnecting... - - - [{0}] password: {1} - {0} will be replaced by password encryption method (string), {1} will be replaced by encrypted password using that method (string) - - - Not starting this bot instance because it's disabled in config file! - - - 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! - {0} will be replaced by maximum allowed number of failed 2FA attempts - - - Logged off of Steam: {0} - {0} will be replaced by logging off reason (string) - - - Successfully logged on as {0}. - {0} will be replaced by steam ID (number) - - - Logging in... - - - This account seems to be used in another ASF instance, which is undefined behaviour, refusing to keep it running! - - - Trade offer failed! - - - Trade couldn't be sent because there is no user with master permission defined! - - - Trade offer sent successfully! - - - You can't send a trade to yourself! - - - This bot doesn't have ASF 2FA enabled! Did you forget to import your authenticator as ASF 2FA? - - - This bot instance is not connected! - - - Not owned yet: {0} - {0} will be replaced by query (string) - - - Owned already: {0} | {1} - {0} will be replaced by game's ID (number), {1} will be replaced by game's name - - - Points balance: {0} - {0} will be replaced by the points balance value (integer) - - - Rate limit exceeded, we will retry after {0} of cooldown... - {0} will be replaced by translated TimeSpan string (such as "25 minutes") - - - Reconnecting... - - - Key: {0} | Status: {1} - {0} will be replaced by cd-key (string), {1} will be replaced by status string - - - Key: {0} | Status: {1} | Items: {2} - {0} will be replaced by cd-key (string), {1} will be replaced by status string, {2} will be replaced by list of key-value pairs, separated by a comma - - - Removed expired login key! - - - Bot is not farming anything. - - - Bot is limited and can't drop any cards through farming. - - - Bot is connecting to Steam network. - - - Bot is not running. - - - Bot is paused or running in manual mode. - - - Bot is currently being used. - - - Unable to login to Steam: {0}/{1} - {0} will be replaced by failure reason (string), {1} will be replaced by extended failure reason (string) - - - {0} is empty! - {0} will be replaced by object's name - - - Unused keys: {0} - {0} will be replaced by list of cd-keys (strings), separated by a comma - - - Failed due to error: {0} - {0} will be replaced by failure reason (string) - - - Connection to Steam Network lost. Reconnecting... - - - Account is no longer occupied: farming process resumed! - - - Account is currently being used: ASF will resume farming when it's free... - - - Connecting... - - - Failed to disconnect the client. Abandoning this bot instance! - - - Could not initialize SteamDirectory: connecting with Steam Network might take much longer than usual! - - - Stopping... - - - Your bot config is invalid. Please verify content of {0} and try again! - {0} will be replaced by file's path - - - Persistent database could not be loaded, if issue persists, please remove {0} in order to recreate the database! - {0} will be replaced by file's path - - - Initializing {0}... - {0} will be replaced by service name that is being initialized - - - Please review our privacy policy section on the wiki if you're concerned about what ASF is in fact doing! - - - It looks like it's your first launch of the program, welcome! - - - Your provided CurrentCulture is invalid, ASF will keep running with the default one! - - - 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? - {0} will be replaced by culture code, such as "en-US", {1} will be replaced by completeness percentage, such as "78.5%" - - - Farming {0} ({1}) is temporarily disabled, as ASF is not able to play that game at the moment. - {0} will be replaced by game's ID (number), {1} will be replaced by game's name - - - ASF detected ID mismatch for {0} ({1}) and will use ID of {2} instead. - {0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by game's ID (number) - - - {0} V{1} - {0} will be replaced by program's name (e.g. "ASF"), {1} will be replaced by program's version (e.g. "1.0.0.0"). This string typically has nothing to translate and you should leave it as it is, unless you need to change the format, e.g. in RTL languages. - - - This account is locked, farming process is permanently unavailable! - - - Bot is locked and can't drop any cards through farming. - - - This function is available only in headless mode! - - - Owned already: {0} - {0} will be replaced by game's ID (number), {1} will be replaced by game's name - - - Access denied! - - - 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. - - - Current memory usage: {0} MB. + {0} will be replaced by function name, {1} will be replaced by exception message, {2} will be replaced by entire stack trace. Please note that this string should include newlines for formatting. + + + Exiting with nonzero error code! + + + Request failing: {0} + {0} will be replaced by URL of the request + + + 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. + {0} will be replaced by file's path + + + {0} is invalid! + {0} will be replaced by object's name + + + No bots are defined. Did you forget to configure your ASF? + + + {0} is null! + {0} will be replaced by object's name + + + Parsing {0} failed! + {0} will be replaced by object's name + + + Request failed after {0} attempts! + {0} will be replaced by maximum number of tries + + + Could not check latest version! + + + Could not proceed with update because there is no asset that relates to currently running version! Automatic update to that version is not possible. + + + Could not proceed with an update because that version doesn't include any assets! + + + Received a request for user input, but process is running in headless mode! + + + Exiting... + + + Failed! + + + Global config file has been changed! + + + Global config file has been removed! + + + Ignoring trade: {0} + {0} will be replaced by trade number + + + Logging in to {0}... + {0} will be replaced by service's name + + + No bots are running, exiting... + + + Refreshing our session! + + + Rejecting trade: {0} + {0} will be replaced by trade number + + + Restarting... + + + Starting... + + + Success! + + + Unlocking parental account... + + + Checking for new version... + + + Downloading new version: {0} ({1} MB)... While waiting, consider donating if you appreciate the work being done! :) + {0} will be replaced by version string, {1} will be replaced by update size (in megabytes) + + + Update process finished! + + + New ASF version is available! Consider updating yourself! + + + Local version: {0} | Remote version: {1} + {0} will be replaced by current version, {1} will be replaced by remote version + + + Please enter your 2FA code from your Steam authenticator app: + Please note that this translation should end with space + + + Please enter SteamGuard auth code that was sent on your e-mail: + Please note that this translation should end with space + + + Please enter your Steam login: + Please note that this translation should end with space + + + Please enter Steam parental code: + Please note that this translation should end with space + + + Please enter your Steam password: + Please note that this translation should end with space + + + Received unknown value for {0}, please report this: {1} + {0} will be replaced by object's name, {1} will be replaced by value for that object + + + IPC server ready! + + + Starting IPC server... + + + This bot has already stopped! + + + Couldn't find any bot named {0}! + {0} will be replaced by bot's name query (string) + + + There are {0}/{1} bots running, with total of {2} games ({3} cards) left to farm. + {0} will be replaced by number of active bots, {1} will be replaced by total number of bots, {2} will be replaced by total number of games left to farm, {3} will be replaced by total number of cards left to farm + + + Bot is farming game: {0} ({1}, {2} card drops remaining) from a total of {3} games ({4} cards) left to farm (~{5} remaining). + {0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm, {3} will be replaced by total number of games to farm, {4} will be replaced by total number of cards to farm, {5} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes") + + + Bot is farming games: {0} from a total of {1} games ({2} cards) left to farm (~{3} remaining). + {0} will be replaced by list of the games (IDs, numbers), {1} will be replaced by total number of games to farm, {2} will be replaced by total number of cards to farm, {3} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes") + + + Checking first badge page... + + + Checking other badge pages... + + + Chosen farming algorithm: {0} + {0} will be replaced by the name of chosen farming algorithm + + + Done! + + + We have a total of {0} games ({1} cards) left to farm (~{2} remaining)... + {0} will be replaced by number of games, {1} will be replaced by number of cards, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes") + + + Farming finished! + + + Finished farming: {0} ({1}) after {2} of playtime! + {0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by translated TimeSpan string (such as "1 day, 5 hours and 30 minutes") + + + Finished farming games: {0} + {0} will be replaced by list of the games (IDs, numbers), separated by a comma + + + Farming status for {0} ({1}): {2} cards remaining + {0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by number of cards left to farm + + + Farming stopped! + + + Ignoring this request, as permanent pause is enabled! + + + We don't have anything to farm on this account! + + + Now farming: {0} ({1}) + {0} will be replaced by game's ID (number), {1} will be replaced by game's name + + + Now farming: {0} + {0} will be replaced by list of the games (IDs, numbers), separated by a comma + + + Playing is currently unavailable, we'll try again later! + + + Still farming: {0} ({1}) + {0} will be replaced by game's ID (number), {1} will be replaced by game's name + + + Still farming: {0} + {0} will be replaced by list of the games (IDs, numbers), separated by a comma + + + Stopped farming: {0} ({1}) + {0} will be replaced by game's ID (number), {1} will be replaced by game's name + + + Stopped farming: {0} + {0} will be replaced by list of the games (IDs, numbers), separated by a comma + + + Unknown command! + + + Could not get badges' information, we will try again later! + + + Could not check cards status for: {0} ({1}), we will try again later! + {0} will be replaced by game's ID (number), {1} will be replaced by game's name + + + Accepting gift: {0}... + {0} will be replaced by giftID (number) + + + This account is limited, farming process is unavailable until the restriction is removed! + + + ID: {0} | Status: {1} + {0} will be replaced by game's ID (number), {1} will be replaced by status string + + + ID: {0} | Status: {1} | Items: {2} + {0} will be replaced by game's ID (number), {1} will be replaced by status string, {2} will be replaced by list of granted IDs (numbers), separated by a comma + + + This bot is already running! + + + Converting .maFile into ASF format... + + + Successfully finished importing mobile authenticator! + + + 2FA Token: {0} + {0} will be replaced by generated 2FA token (string) + + + Automatic farming has paused! + + + Automatic farming has resumed! + + + Automatic farming is paused already! + + + Automatic farming is resumed already! + + + Connected to Steam! + + + Disconnected from Steam! + + + Disconnecting... + + + [{0}] password: {1} + {0} will be replaced by password encryption method (string), {1} will be replaced by encrypted password using that method (string) + + + Not starting this bot instance because it's disabled in config file! + + + 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! + {0} will be replaced by maximum allowed number of failed 2FA attempts + + + Logged off of Steam: {0} + {0} will be replaced by logging off reason (string) + + + Successfully logged on as {0}. + {0} will be replaced by steam ID (number) + + + Logging in... + + + This account seems to be used in another ASF instance, which is undefined behaviour, refusing to keep it running! + + + Trade offer failed! + + + Trade couldn't be sent because there is no user with master permission defined! + + + Trade offer sent successfully! + + + You can't send a trade to yourself! + + + This bot doesn't have ASF 2FA enabled! Did you forget to import your authenticator as ASF 2FA? + + + This bot instance is not connected! + + + Not owned yet: {0} + {0} will be replaced by query (string) + + + Owned already: {0} | {1} + {0} will be replaced by game's ID (number), {1} will be replaced by game's name + + + Points balance: {0} + {0} will be replaced by the points balance value (integer) + + + Rate limit exceeded, we will retry after {0} of cooldown... + {0} will be replaced by translated TimeSpan string (such as "25 minutes") + + + Reconnecting... + + + Key: {0} | Status: {1} + {0} will be replaced by cd-key (string), {1} will be replaced by status string + + + Key: {0} | Status: {1} | Items: {2} + {0} will be replaced by cd-key (string), {1} will be replaced by status string, {2} will be replaced by list of key-value pairs, separated by a comma + + + Removed expired login key! + + + Bot is not farming anything. + + + Bot is limited and can't drop any cards through farming. + + + Bot is connecting to Steam network. + + + Bot is not running. + + + Bot is paused or running in manual mode. + + + Bot is currently being used. + + + Unable to login to Steam: {0}/{1} + {0} will be replaced by failure reason (string), {1} will be replaced by extended failure reason (string) + + + {0} is empty! + {0} will be replaced by object's name + + + Unused keys: {0} + {0} will be replaced by list of cd-keys (strings), separated by a comma + + + Failed due to error: {0} + {0} will be replaced by failure reason (string) + + + Connection to Steam Network lost. Reconnecting... + + + Account is no longer occupied: farming process resumed! + + + Account is currently being used: ASF will resume farming when it's free... + + + Connecting... + + + Failed to disconnect the client. Abandoning this bot instance! + + + Could not initialize SteamDirectory: connecting with Steam Network might take much longer than usual! + + + Stopping... + + + Your bot config is invalid. Please verify content of {0} and try again! + {0} will be replaced by file's path + + + Persistent database could not be loaded, if issue persists, please remove {0} in order to recreate the database! + {0} will be replaced by file's path + + + Initializing {0}... + {0} will be replaced by service name that is being initialized + + + Please review our privacy policy section on the wiki if you're concerned about what ASF is in fact doing! + + + It looks like it's your first launch of the program, welcome! + + + Your provided CurrentCulture is invalid, ASF will keep running with the default one! + + + 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? + {0} will be replaced by culture code, such as "en-US", {1} will be replaced by completeness percentage, such as "78.5%" + + + Farming {0} ({1}) is temporarily disabled, as ASF is not able to play that game at the moment. + {0} will be replaced by game's ID (number), {1} will be replaced by game's name + + + ASF detected ID mismatch for {0} ({1}) and will use ID of {2} instead. + {0} will be replaced by game's ID (number), {1} will be replaced by game's name, {2} will be replaced by game's ID (number) + + + {0} V{1} + {0} will be replaced by program's name (e.g. "ASF"), {1} will be replaced by program's version (e.g. "1.0.0.0"). This string typically has nothing to translate and you should leave it as it is, unless you need to change the format, e.g. in RTL languages. + + + This account is locked, farming process is permanently unavailable! + + + Bot is locked and can't drop any cards through farming. + + + This function is available only in headless mode! + + + Owned already: {0} + {0} will be replaced by game's ID (number), {1} will be replaced by game's name + + + Access denied! + + + 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. + + + Current memory usage: {0} MB. Process uptime: {1} - {0} will be replaced by number (in megabytes) of memory being used, {1} will be replaced by translated TimeSpan string (such as "25 minutes"). Please note that this string should include newlines for formatting. - - - Clearing Steam discovery queue #{0}... - {0} will be replaced by queue number - - - Done clearing Steam discovery queue #{0}. - {0} will be replaced by queue number - - - {0}/{1} bots already own game {2}. - {0} will be replaced by number of bots that already own particular game being checked, {1} will be replaced by total number of bots that were checked during the process, {2} will be replaced by game's ID (number) - - - Refreshing packages data... - - - Usage of {0} is deprecated and will be removed in future versions of the program. Please use {1} instead. - {0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property) - - - Accepted donation trade: {0} - {0} will be replaced by trade's ID (number) - - - Workaround for {0} bug has been triggered. - {0} will be replaced by the bug's name provided by ASF - - - Target bot instance is not connected! - - - Wallet balance: {0} {1} - {0} will be replaced by wallet balance value, {1} will be replaced by currency name - - - Bot has no wallet. - - - Bot has level {0}. - {0} will be replaced by bot's level - - - Matching Steam items, round #{0}... - {0} will be replaced by round number - - - Done matching Steam items, round #{0}. - {0} will be replaced by round number - - - 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) - - - {0} has been loaded successfully! - {0} will be replaced by the name of the custom ASF plugin - - - Loading {0} V{1}... - {0} will be replaced by the name of the custom ASF plugin, {1} will be replaced by its version - - - Nothing found! - - - 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. - - - Please wait... - - - Enter command: - - - Executing... - - - Interactive console is now active, type 'c' in order to enter command mode. - - - Interactive console is not available due to missing {0} config property. - {0} will be replaced by the name of the missing config property (string) - - - Bot has {0} games remaining in its background queue. - {0} will be replaced by remaining number of games in BGR's queue - - - ASF process is already running for this working directory, aborting! - - - Successfully handled {0} confirmations! - {0} will be replaced by number of confirmations - - - Waiting up to {0} to ensure that we're free to start farming... - {0} will be replaced by translated TimeSpan string (such as "1 minute") - - - Cleaning up old files after update... - - - Generating Steam parental code, this can take a while, consider putting it in the config instead... - - - IPC config has been changed! - - - The trade offer {0} is determined to be {1} due to {2}. - {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 - - - Received InvalidPassword error code {0} times in a row. Your password for this account is most likely wrong, aborting! - {0} will be replaced by maximum allowed number of failed login attempts - - - Result: {0} - {0} will be replaced by generic result of various functions that use this string - - - 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. - - - Unknown command-line argument: {0} - {0} will be replaced by unrecognized command that has been provided - - - Config directory could not be found, aborting! - - - Playing selected {0}: {1} - {0} will be replaced by internal name of the config property (e.g. "GamesPlayedWhileIdle"), {1} will be replaced by comma-separated list of appIDs that user has chosen - - - {0} config file will be migrated to the latest syntax... - {0} will be replaced with the relative path to the affected config file - + {0} will be replaced by number (in megabytes) of memory being used, {1} will be replaced by translated TimeSpan string (such as "25 minutes"). Please note that this string should include newlines for formatting. + + + Clearing Steam discovery queue #{0}... + {0} will be replaced by queue number + + + Done clearing Steam discovery queue #{0}. + {0} will be replaced by queue number + + + {0}/{1} bots already own game {2}. + {0} will be replaced by number of bots that already own particular game being checked, {1} will be replaced by total number of bots that were checked during the process, {2} will be replaced by game's ID (number) + + + Refreshing packages data... + + + Usage of {0} is deprecated and will be removed in future versions of the program. Please use {1} instead. + {0} will be replaced by the name of deprecated property (such as argument, config property or likewise), {1} will be replaced by the name of valid replacement (such as another argument or config property) + + + Accepted donation trade: {0} + {0} will be replaced by trade's ID (number) + + + Workaround for {0} bug has been triggered. + {0} will be replaced by the bug's name provided by ASF + + + Target bot instance is not connected! + + + Wallet balance: {0} {1} + {0} will be replaced by wallet balance value, {1} will be replaced by currency name + + + Bot has no wallet. + + + Bot has level {0}. + {0} will be replaced by bot's level + + + Matching Steam items, round #{0}... + {0} will be replaced by round number + + + Done matching Steam items, round #{0}. + {0} will be replaced by round number + + + 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) + + + {0} has been loaded successfully! + {0} will be replaced by the name of the custom ASF plugin + + + Loading {0} V{1}... + {0} will be replaced by the name of the custom ASF plugin, {1} will be replaced by its version + + + Nothing found! + + + 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. + + + Please wait... + + + Enter command: + + + Executing... + + + Interactive console is now active, type 'c' in order to enter command mode. + + + Interactive console is not available due to missing {0} config property. + {0} will be replaced by the name of the missing config property (string) + + + Bot has {0} games remaining in its background queue. + {0} will be replaced by remaining number of games in BGR's queue + + + ASF process is already running for this working directory, aborting! + + + Successfully handled {0} confirmations! + {0} will be replaced by number of confirmations + + + Waiting up to {0} to ensure that we're free to start farming... + {0} will be replaced by translated TimeSpan string (such as "1 minute") + + + Cleaning up old files after update... + + + Generating Steam parental code, this can take a while, consider putting it in the config instead... + + + IPC config has been changed! + + + The trade offer {0} is determined to be {1} due to {2}. + {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 + + + Received InvalidPassword error code {0} times in a row. Your password for this account is most likely wrong, aborting! + {0} will be replaced by maximum allowed number of failed login attempts + + + Result: {0} + {0} will be replaced by generic result of various functions that use this string + + + 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. + + + Unknown command-line argument: {0} + {0} will be replaced by unrecognized command that has been provided + + + Config directory could not be found, aborting! + + + Playing selected {0}: {1} + {0} will be replaced by internal name of the config property (e.g. "GamesPlayedWhileIdle"), {1} will be replaced by comma-separated list of appIDs that user has chosen + + + {0} config file will be migrated to the latest syntax... + {0} will be replaced with the relative path to the affected config file + diff --git a/ArchiSteamFarm/NLog/ArchiLogger.cs b/ArchiSteamFarm/NLog/ArchiLogger.cs index 30645d6fe..147834ea9 100644 --- a/ArchiSteamFarm/NLog/ArchiLogger.cs +++ b/ArchiSteamFarm/NLog/ArchiLogger.cs @@ -149,12 +149,15 @@ namespace ArchiSteamFarm.NLog { loggedMessage.Append(steamID); } - LogEventInfo logEventInfo = new(LogLevel.Trace, Logger.Name, loggedMessage.ToString()); - logEventInfo.Properties["Echo"] = echo; - logEventInfo.Properties["Message"] = message; - logEventInfo.Properties["ChatGroupID"] = chatGroupID; - logEventInfo.Properties["ChatID"] = chatID; - logEventInfo.Properties["SteamID"] = steamID; + LogEventInfo logEventInfo = new(LogLevel.Trace, Logger.Name, loggedMessage.ToString()) { + Properties = { + ["Echo"] = echo, + ["Message"] = message, + ["ChatGroupID"] = chatGroupID, + ["ChatID"] = chatID, + ["SteamID"] = steamID + } + }; Logger.Log(logEventInfo); } @@ -220,11 +223,13 @@ namespace ArchiSteamFarm.NLog { string loggedMessage = previousMethodName + "() " + steamID.AccountType + " " + steamID64 + (handled.HasValue ? " = " + handled.Value : ""); - LogEventInfo logEventInfo = new(LogLevel.Trace, Logger.Name, loggedMessage); - - logEventInfo.Properties["AccountType"] = steamID.AccountType; - logEventInfo.Properties["Handled"] = handled; - logEventInfo.Properties["SteamID"] = steamID64; + LogEventInfo logEventInfo = new(LogLevel.Trace, Logger.Name, loggedMessage) { + Properties = { + ["AccountType"] = steamID.AccountType, + ["Handled"] = handled, + ["SteamID"] = steamID64 + } + }; Logger.Log(logEventInfo); } diff --git a/ArchiSteamFarm/NLog/Logging.cs b/ArchiSteamFarm/NLog/Logging.cs index 60a59dfaa..f23607f05 100644 --- a/ArchiSteamFarm/NLog/Logging.cs +++ b/ArchiSteamFarm/NLog/Logging.cs @@ -141,6 +141,7 @@ namespace ArchiSteamFarm.NLog { ConsoleSemaphore.Release(); } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework return !string.IsNullOrEmpty(result) ? result!.Trim() : null; } @@ -330,13 +331,17 @@ namespace ArchiSteamFarm.NLog { string? commandPrefix = ASF.GlobalConfig != null ? ASF.GlobalConfig.CommandPrefix : GlobalConfig.DefaultCommandPrefix; + // ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework if (!string.IsNullOrEmpty(commandPrefix) && command!.StartsWith(commandPrefix!, StringComparison.Ordinal)) { + // ReSharper restore RedundantSuppressNullableWarningExpression - required for .NET Framework + + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (command.Length == commandPrefix!.Length) { // If the message starts with command prefix and is of the same length as command prefix, then it's just empty command trigger, useless continue; } - command = command[commandPrefix!.Length..]; + command = command[commandPrefix.Length..]; } Bot? targetBot = Bot.Bots?.OrderBy(bot => bot.Key, Bot.BotsComparer).Select(bot => bot.Value).FirstOrDefault(); diff --git a/ArchiSteamFarm/NLog/Targets/SteamTarget.cs b/ArchiSteamFarm/NLog/Targets/SteamTarget.cs index 273b7ad91..5166d705c 100644 --- a/ArchiSteamFarm/NLog/Targets/SteamTarget.cs +++ b/ArchiSteamFarm/NLog/Targets/SteamTarget.cs @@ -79,6 +79,7 @@ namespace ArchiSteamFarm.NLog.Targets { string? botName = BotName?.Render(logEvent); if (!string.IsNullOrEmpty(botName)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework bot = Bot.GetBot(botName!); if (bot?.IsConnectedAndLoggedOn != true) { diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 6bda809f7..fec42da10 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -202,6 +202,7 @@ namespace ArchiSteamFarm { string? copyright = Assembly.GetExecutingAssembly().GetCustomAttribute()?.Copyright; if (!string.IsNullOrEmpty(copyright)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework ASF.ArchiLogger.LogGenericInfo(copyright!); } @@ -277,7 +278,10 @@ namespace ArchiSteamFarm { if (!string.IsNullOrEmpty(latestJson)) { ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.AutomaticFileMigration, globalConfigFile)); + + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework await SerializableFile.Write(globalConfigFile, latestJson!).ConfigureAwait(false); + ASF.ArchiLogger.LogGenericInfo(Strings.Done); } @@ -475,19 +479,19 @@ namespace ArchiSteamFarm { string? envCryptKey = Environment.GetEnvironmentVariable(SharedInfo.EnvironmentVariableCryptKey); if (!string.IsNullOrEmpty(envCryptKey)) { - HandleCryptKeyArgument(envCryptKey!); + HandleCryptKeyArgument(envCryptKey); } string? envNetworkGroup = Environment.GetEnvironmentVariable(SharedInfo.EnvironmentVariableNetworkGroup); if (!string.IsNullOrEmpty(envNetworkGroup)) { - HandleNetworkGroupArgument(envNetworkGroup!); + HandleNetworkGroupArgument(envNetworkGroup); } string? envPath = Environment.GetEnvironmentVariable(SharedInfo.EnvironmentVariablePath); if (!string.IsNullOrEmpty(envPath)) { - HandlePathArgument(envPath!); + HandlePathArgument(envPath); } } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); diff --git a/ArchiSteamFarm/SharedInfo.cs b/ArchiSteamFarm/SharedInfo.cs index f794d3031..322cb5963 100644 --- a/ArchiSteamFarm/SharedInfo.cs +++ b/ArchiSteamFarm/SharedInfo.cs @@ -68,6 +68,7 @@ namespace ArchiSteamFarm { internal static string HomeDirectory { get { if (!string.IsNullOrEmpty(CachedHomeDirectory)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework return CachedHomeDirectory!; } diff --git a/ArchiSteamFarm/Steam/Bot.cs b/ArchiSteamFarm/Steam/Bot.cs index eeea9a5f6..e9ed8670f 100644 --- a/ArchiSteamFarm/Steam/Bot.cs +++ b/ArchiSteamFarm/Steam/Bot.cs @@ -1058,6 +1058,7 @@ namespace ArchiSteamFarm.Steam { if (!string.IsNullOrEmpty(releaseState)) { // We must convert this to uppercase, since Valve doesn't stick to any convention and we can have a case mismatch + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework switch (releaseState!.ToUpperInvariant()) { case "RELEASED": break; @@ -1078,6 +1079,7 @@ namespace ArchiSteamFarm.Steam { } // We must convert this to uppercase, since Valve doesn't stick to any convention and we can have a case mismatch + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework switch (type!.ToUpperInvariant()) { case "APPLICATION": case "EPISODE": @@ -1113,6 +1115,7 @@ namespace ArchiSteamFarm.Steam { return (appID, DateTime.MinValue, true); } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework string[] dlcAppIDsTexts = listOfDlc!.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string dlcAppIDsText in dlcAppIDsTexts) { @@ -1477,7 +1480,10 @@ namespace ArchiSteamFarm.Steam { if (!string.IsNullOrEmpty(latestJson)) { ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.AutomaticFileMigration, configFilePath)); + + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework await SerializableFile.Write(configFilePath, latestJson!).ConfigureAwait(false); + ASF.ArchiLogger.LogGenericInfo(Strings.Done); } @@ -1669,6 +1675,7 @@ namespace ArchiSteamFarm.Steam { string? key = game.Key as string; + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (string.IsNullOrEmpty(key)) { invalid = true; ASF.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(key))); @@ -1959,6 +1966,7 @@ namespace ArchiSteamFarm.Steam { string? steamLogin = await Logging.GetUserInput(ASF.EUserInputType.Login, BotName).ConfigureAwait(false); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (string.IsNullOrEmpty(steamLogin) || !SetUserInput(ASF.EUserInputType.Login, steamLogin!)) { ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(steamLogin))); @@ -1971,6 +1979,7 @@ namespace ArchiSteamFarm.Steam { string? steamPassword = await Logging.GetUserInput(ASF.EUserInputType.Password, BotName).ConfigureAwait(false); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (string.IsNullOrEmpty(steamPassword) || !SetUserInput(ASF.EUserInputType.Password, steamPassword!)) { ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(steamPassword))); @@ -2003,7 +2012,7 @@ namespace ArchiSteamFarm.Steam { if ((BotConfig.SendTradePeriod > 0) && (BotConfig.LootableTypes.Count > 0) && BotConfig.SteamUserPermissions.Values.Any(permission => permission >= BotConfig.EAccess.Master)) { SendItemsTimer = new Timer( - async _ => await Actions.SendInventory(filterFunction: item => BotConfig.LootableTypes.Contains(item.Type)).ConfigureAwait(false), + OnSendItemsTimer, null, TimeSpan.FromHours(BotConfig.SendTradePeriod) + TimeSpan.FromSeconds(ASF.LoadBalancingDelay * Bots.Count), // Delay TimeSpan.FromHours(BotConfig.SendTradePeriod) // Period @@ -2187,6 +2196,7 @@ namespace ArchiSteamFarm.Steam { loginKey = BotDatabase.LoginKey; // Decrypt login key if needed + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (!string.IsNullOrEmpty(loginKey) && (loginKey!.Length > 19) && (BotConfig.PasswordFormat != ArchiCryptoHelper.ECryptoMethod.PlainText)) { loginKey = ArchiCryptoHelper.Decrypt(BotConfig.PasswordFormat, loginKey); } @@ -2221,6 +2231,7 @@ namespace ArchiSteamFarm.Steam { string? password = BotConfig.DecryptedSteamPassword; if (!string.IsNullOrEmpty(password)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework password = Regex.Replace(password!, nonAsciiPattern, "", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); if (string.IsNullOrEmpty(password)) { @@ -2658,6 +2669,7 @@ namespace ArchiSteamFarm.Steam { string? authCode = await Logging.GetUserInput(ASF.EUserInputType.SteamGuard, BotName).ConfigureAwait(false); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (string.IsNullOrEmpty(authCode) || !SetUserInput(ASF.EUserInputType.SteamGuard, authCode!)) { ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(authCode))); @@ -2671,6 +2683,7 @@ namespace ArchiSteamFarm.Steam { string? twoFactorCode = await Logging.GetUserInput(ASF.EUserInputType.TwoFactorAuthentication, BotName).ConfigureAwait(false); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (string.IsNullOrEmpty(twoFactorCode) || !SetUserInput(ASF.EUserInputType.TwoFactorAuthentication, twoFactorCode!)) { ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(twoFactorCode))); @@ -2722,6 +2735,7 @@ namespace ArchiSteamFarm.Steam { if (!string.IsNullOrEmpty(steamParentalCode)) { if (BotConfig.SteamParentalCode != steamParentalCode) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (!SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode!)) { ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(steamParentalCode))); @@ -2735,6 +2749,7 @@ namespace ArchiSteamFarm.Steam { steamParentalCode = await Logging.GetUserInput(ASF.EUserInputType.SteamParentalCode, BotName).ConfigureAwait(false); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (string.IsNullOrEmpty(steamParentalCode) || !SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode!)) { ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(steamParentalCode))); @@ -2751,6 +2766,7 @@ namespace ArchiSteamFarm.Steam { string? steamParentalCode = await Logging.GetUserInput(ASF.EUserInputType.SteamParentalCode, BotName).ConfigureAwait(false); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (string.IsNullOrEmpty(steamParentalCode) || !SetUserInput(ASF.EUserInputType.SteamParentalCode, steamParentalCode!)) { ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(steamParentalCode))); @@ -2983,6 +2999,8 @@ namespace ArchiSteamFarm.Steam { await CheckOccupationStatus().ConfigureAwait(false); } + private async void OnSendItemsTimer(object? state) => await Actions.SendInventory(filterFunction: item => BotConfig.LootableTypes.Contains(item.Type)).ConfigureAwait(false); + private async void OnServiceMethod(SteamUnifiedMessages.ServiceMethodNotification notification) { if (notification == null) { throw new ArgumentNullException(nameof(notification)); @@ -3118,6 +3136,7 @@ namespace ArchiSteamFarm.Steam { break; } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework PurchaseResponseCallback? result = await Actions.RedeemKey(key!).ConfigureAwait(false); if (result == null) { @@ -3126,6 +3145,7 @@ namespace ArchiSteamFarm.Steam { if (((result.PurchaseResultDetail == EPurchaseResultDetail.CannotRedeemCodeFromClient) || ((result.PurchaseResultDetail == EPurchaseResultDetail.BadActivationCode) && assumeWalletKeyOnBadActivationCode)) && (WalletCurrency != ECurrencyCode.Invalid)) { // If it's a wallet code, we try to redeem it first, then handle the inner result as our primary one + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework (EResult Result, EPurchaseResultDetail? PurchaseResult)? walletResult = await ArchiWebHandler.RedeemWalletKey(key!).ConfigureAwait(false); if (walletResult != null) { @@ -3170,9 +3190,11 @@ namespace ArchiSteamFarm.Steam { break; } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework BotDatabase.RemoveGameToRedeemInBackground(key!); // If user omitted the name or intentionally provided the same name as key, replace it with the Steam result + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (name!.Equals(key, StringComparison.OrdinalIgnoreCase) && (result.Items?.Count > 0)) { name = string.Join(", ", result.Items.Values); } diff --git a/ArchiSteamFarm/Steam/Data/InventoryResponse.cs b/ArchiSteamFarm/Steam/Data/InventoryResponse.cs index a1d5b2fc6..b6c6d892f 100644 --- a/ArchiSteamFarm/Steam/Data/InventoryResponse.cs +++ b/ArchiSteamFarm/Steam/Data/InventoryResponse.cs @@ -107,7 +107,7 @@ namespace ArchiSteamFarm.Steam.Data { foreach (Tag tag in Tags) { switch (tag.Identifier) { case "Game": - if (string.IsNullOrEmpty(tag.Value) || (tag.Value!.Length <= 4) || !tag.Value.StartsWith("app_", StringComparison.Ordinal)) { + if (string.IsNullOrEmpty(tag.Value) || (tag.Value.Length <= 4) || !tag.Value.StartsWith("app_", StringComparison.Ordinal)) { ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(tag.Value), tag.Value)); break; diff --git a/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs b/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs index a57623a0e..7894685f8 100644 --- a/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs +++ b/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs @@ -324,7 +324,10 @@ namespace ArchiSteamFarm.Steam.Integration { // Extra entry for format Dictionary arguments = new(5, StringComparer.Ordinal) { { "include_appinfo", 1 }, + + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework { "key", steamApiKey! }, + { "skip_unvetted_apps", "0" }, { "steamid", steamID } }; @@ -378,6 +381,7 @@ namespace ArchiSteamFarm.Steam.Integration { return null; } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework result[appID] = gameName!; } @@ -394,7 +398,9 @@ namespace ArchiSteamFarm.Steam.Integration { // Extra entry for format Dictionary arguments = new(3, StringComparer.Ordinal) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework { "access_token", accessToken! }, + { "steamid", Bot.SteamID } }; @@ -547,7 +553,7 @@ namespace ArchiSteamFarm.Steam.Integration { } // This is actually client error with a reason, so it doesn't make sense to retry - Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content!.ErrorText)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.ErrorText)); return (false, mobileTradeOfferIDs); } @@ -950,8 +956,10 @@ namespace ArchiSteamFarm.Steam.Integration { }; if (data != null) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework data[sessionName] = sessionID!; } else { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework data = new Dictionary(1, StringComparer.Ordinal) { { sessionName, sessionID! } }; } } @@ -1054,8 +1062,10 @@ namespace ArchiSteamFarm.Steam.Integration { }; if (data != null) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework data[sessionName] = sessionID!; } else { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework data = new Dictionary(1, StringComparer.Ordinal) { { sessionName, sessionID! } }; } } @@ -1157,6 +1167,7 @@ namespace ArchiSteamFarm.Steam.Integration { _ => throw new ArgumentOutOfRangeException(nameof(session)) }; + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework KeyValuePair sessionValue = new(sessionName, sessionID!); if (data != null) { @@ -1265,8 +1276,10 @@ namespace ArchiSteamFarm.Steam.Integration { }; if (data != null) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework data[sessionName] = sessionID!; } else { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework data = new Dictionary(1, StringComparer.Ordinal) { { sessionName, sessionID! } }; } } @@ -1410,7 +1423,7 @@ namespace ArchiSteamFarm.Steam.Integration { } // This is actually client error with a reason, so it doesn't make sense to retry - Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content!.ErrorText)); + Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, response.Content.ErrorText)); return (false, false); } @@ -1499,7 +1512,9 @@ namespace ArchiSteamFarm.Steam.Integration { // Extra entry for format Dictionary arguments = new(3, StringComparer.Ordinal) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework { "key", steamApiKey! }, + { "tradeofferid", tradeID } }; @@ -1559,7 +1574,10 @@ namespace ArchiSteamFarm.Steam.Integration { { "active_only", 1 }, { "get_descriptions", 1 }, { "get_received_offers", 1 }, + + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework { "key", steamApiKey! }, + { "time_historical_cutoff", uint.MaxValue } }; @@ -1649,7 +1667,8 @@ namespace ArchiSteamFarm.Steam.Integration { return null; } - parsedTags.Add(new Tag(identifier!, value!)); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework + parsedTags.Add(new Tag(identifier!, value)); } parsedDescription.Tags = parsedTags.ToImmutableHashSet(); @@ -2044,11 +2063,14 @@ namespace ArchiSteamFarm.Steam.Integration { // Extra entry for format Dictionary arguments = new(!string.IsNullOrEmpty(tradeToken) ? 4 : 3, StringComparer.Ordinal) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework { "key", steamApiKey! }, + { "steamid_target", steamID } }; if (!string.IsNullOrEmpty(tradeToken)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework arguments["trade_offer_access_token"] = tradeToken!; } @@ -2456,7 +2478,7 @@ namespace ArchiSteamFarm.Steam.Integration { return (ESteamApiKeyState.AccessDenied, null); } - IElement? htmlNode = response!.Content!.SelectSingleNode("//div[@id='bodyContents_ex']/p"); + IElement? htmlNode = response.Content.SelectSingleNode("//div[@id='bodyContents_ex']/p"); if (htmlNode == null) { Bot.ArchiLogger.LogNullError(nameof(htmlNode)); @@ -2709,6 +2731,7 @@ namespace ArchiSteamFarm.Steam.Integration { ObjectResponse? response = await UrlGetToJsonObjectWithSession(request).ConfigureAwait(false); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework return !string.IsNullOrEmpty(response?.Content.Data.WebAPIToken) ? (true, response!.Content.Data.WebAPIToken) : (false, null); } @@ -2810,6 +2833,8 @@ namespace ArchiSteamFarm.Steam.Integration { Dictionary data = new(2, StringComparer.Ordinal) { { "pin", parentalCode }, + + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework { "sessionid", sessionID! } }; diff --git a/ArchiSteamFarm/Steam/Integration/SteamChatMessage.cs b/ArchiSteamFarm/Steam/Integration/SteamChatMessage.cs index fd6285816..7f6ec4944 100644 --- a/ArchiSteamFarm/Steam/Integration/SteamChatMessage.cs +++ b/ArchiSteamFarm/Steam/Integration/SteamChatMessage.cs @@ -51,6 +51,7 @@ namespace ArchiSteamFarm.Steam.Integration { if (!string.IsNullOrEmpty(steamMessagePrefix)) { // We must escape our message prefix if needed + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework steamMessagePrefix = Escape(steamMessagePrefix!); prefixBytes = GetMessagePrefixBytes(steamMessagePrefix); diff --git a/ArchiSteamFarm/Steam/Interaction/Actions.cs b/ArchiSteamFarm/Steam/Interaction/Actions.cs index 5a8b3ce40..9aafe0d62 100644 --- a/ArchiSteamFarm/Steam/Interaction/Actions.cs +++ b/ArchiSteamFarm/Steam/Interaction/Actions.cs @@ -500,7 +500,7 @@ namespace ArchiSteamFarm.Steam.Interaction { internal void OnDisconnected() => HandledGifts.Clear(); private ulong GetFirstSteamMasterID() { - ulong steamMasterID = Bot.BotConfig.SteamUserPermissions.Where(kv => (kv.Key > 0) && (kv.Key != Bot.SteamID) && new SteamID(kv.Key).IsIndividualAccount && (kv.Value == BotConfig.EAccess.Master)).Select(kv => kv.Key).OrderBy(steamID => steamID).FirstOrDefault()!; + ulong steamMasterID = Bot.BotConfig.SteamUserPermissions.Where(kv => (kv.Key > 0) && (kv.Key != Bot.SteamID) && new SteamID(kv.Key).IsIndividualAccount && (kv.Value == BotConfig.EAccess.Master)).Select(kv => kv.Key).OrderBy(steamID => steamID).FirstOrDefault(); if (steamMasterID > 0) { return steamMasterID; diff --git a/ArchiSteamFarm/Steam/Interaction/Commands.cs b/ArchiSteamFarm/Steam/Interaction/Commands.cs index 4acc97397..6cfc7aa75 100644 --- a/ArchiSteamFarm/Steam/Interaction/Commands.cs +++ b/ArchiSteamFarm/Steam/Interaction/Commands.cs @@ -333,10 +333,12 @@ namespace ArchiSteamFarm.Steam.Interaction { string? commandPrefix = ASF.GlobalConfig != null ? ASF.GlobalConfig.CommandPrefix : GlobalConfig.DefaultCommandPrefix; if (!string.IsNullOrEmpty(commandPrefix)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (!message.StartsWith(commandPrefix!, StringComparison.Ordinal)) { string? pluginsResponse = await PluginsCore.OnBotMessage(Bot, steamID, message).ConfigureAwait(false); if (!string.IsNullOrEmpty(pluginsResponse)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (!await Bot.SendMessage(steamID, pluginsResponse!).ConfigureAwait(false)) { Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(Bot.SendMessage))); Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.Content, pluginsResponse)); @@ -346,6 +348,7 @@ namespace ArchiSteamFarm.Steam.Interaction { return; } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (message.Length == commandPrefix!.Length) { // If the message starts with command prefix and is of the same length as command prefix, then it's just empty command trigger, useless return; @@ -381,6 +384,7 @@ namespace ArchiSteamFarm.Steam.Interaction { response = FormatBotResponse(Strings.UnknownCommand); } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (!await Bot.SendMessage(steamID, response!).ConfigureAwait(false)) { Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(Bot.SendMessage))); Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.Content, response)); @@ -407,10 +411,12 @@ namespace ArchiSteamFarm.Steam.Interaction { string? commandPrefix = ASF.GlobalConfig != null ? ASF.GlobalConfig.CommandPrefix : GlobalConfig.DefaultCommandPrefix; if (!string.IsNullOrEmpty(commandPrefix)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (!message.StartsWith(commandPrefix!, StringComparison.Ordinal)) { string? pluginsResponse = await PluginsCore.OnBotMessage(Bot, steamID, message).ConfigureAwait(false); if (!string.IsNullOrEmpty(pluginsResponse)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (!await Bot.SendMessage(chatGroupID, chatID, pluginsResponse!).ConfigureAwait(false)) { Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(Bot.SendMessage))); Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.Content, pluginsResponse)); @@ -420,6 +426,7 @@ namespace ArchiSteamFarm.Steam.Interaction { return; } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (message.Length == commandPrefix!.Length) { // If the message starts with command prefix and is of the same length as command prefix, then it's just empty command trigger, useless return; @@ -457,6 +464,7 @@ namespace ArchiSteamFarm.Steam.Interaction { response = FormatBotResponse(Strings.UnknownCommand); } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (!await Bot.SendMessage(chatGroupID, chatID, response!).ConfigureAwait(false)) { Bot.ArchiLogger.LogGenericWarning(string.Format(CultureInfo.CurrentCulture, Strings.WarningFailedWithError, nameof(Bot.SendMessage))); Bot.ArchiLogger.LogGenericDebug(string.Format(CultureInfo.CurrentCulture, Strings.Content, response)); @@ -2659,6 +2667,7 @@ namespace ArchiSteamFarm.Steam.Interaction { string? previousKey = key; while (!string.IsNullOrEmpty(key)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework string startingKey = key!; using (IEnumerator botsEnumerator = Bot.Bots.Where(bot => (bot.Value != Bot) && bot.Value.IsConnectedAndLoggedOn && bot.Value.Commands.Bot.HasAccess(steamID, BotConfig.EAccess.Operator)).OrderByDescending(bot => Bot.BotsComparer?.Compare(bot.Key, Bot.BotName) > 0).ThenBy(bot => bot.Key, Bot.BotsComparer).Select(bot => bot.Value).GetEnumerator()) { @@ -2670,6 +2679,7 @@ namespace ArchiSteamFarm.Steam.Interaction { previousKey = key; } + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework if (redeemFlags.HasFlag(ERedeemFlags.Validate) && !Utilities.IsValidCdKey(key!)) { // Next key key = keysEnumerator.MoveNext() ? keysEnumerator.Current : null; @@ -2684,6 +2694,7 @@ namespace ArchiSteamFarm.Steam.Interaction { } else { bool skipRequest = triedBots.Contains(currentBot) || rateLimitedBots.Contains(currentBot); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework PurchaseResponseCallback? result = skipRequest ? new PurchaseResponseCallback(EResult.Fail, EPurchaseResultDetail.CancelledByUser) : await currentBot.Actions.RedeemKey(key!).ConfigureAwait(false); if (result == null) { @@ -2697,6 +2708,7 @@ namespace ArchiSteamFarm.Steam.Interaction { if ((result.PurchaseResultDetail == EPurchaseResultDetail.CannotRedeemCodeFromClient) || ((result.PurchaseResultDetail == EPurchaseResultDetail.BadActivationCode) && assumeWalletKeyOnBadActivationCode)) { if (Bot.WalletCurrency != ECurrencyCode.Invalid) { // If it's a wallet code, we try to redeem it first, then handle the inner result as our primary one + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework (EResult Result, EPurchaseResultDetail? PurchaseResult)? walletResult = await currentBot.ArchiWebHandler.RedeemWalletKey(key!).ConfigureAwait(false); if (walletResult != null) { @@ -2725,6 +2737,7 @@ namespace ArchiSteamFarm.Steam.Interaction { case EPurchaseResultDetail.NoDetail: // OK case EPurchaseResultDetail.Timeout: if ((result.Result != EResult.Timeout) && (result.PurchaseResultDetail != EPurchaseResultDetail.Timeout)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework unusedKeys.Remove(key!); } @@ -2761,6 +2774,7 @@ namespace ArchiSteamFarm.Steam.Interaction { bool alreadyHandled = false; foreach (Bot innerBot in Bot.Bots.Where(bot => (bot.Value != currentBot) && (!redeemFlags.HasFlag(ERedeemFlags.SkipInitial) || (bot.Value != Bot)) && !triedBots.Contains(bot.Value) && !rateLimitedBots.Contains(bot.Value) && bot.Value.IsConnectedAndLoggedOn && bot.Value.Commands.Bot.HasAccess(steamID, BotConfig.EAccess.Operator) && ((items.Count == 0) || items.Keys.Any(packageID => !bot.Value.OwnedPackageIDs.ContainsKey(packageID)))).OrderBy(bot => bot.Key, Bot.BotsComparer).Select(bot => bot.Value)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework PurchaseResponseCallback? otherResult = await innerBot.Actions.RedeemKey(key!).ConfigureAwait(false); if (otherResult == null) { @@ -2777,6 +2791,8 @@ namespace ArchiSteamFarm.Steam.Interaction { case EPurchaseResultDetail.NoDetail: // OK // This key is already handled, as we either redeemed it or we're sure it's dupe/invalid alreadyHandled = true; + + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework unusedKeys.Remove(key!); break; @@ -2813,6 +2829,7 @@ namespace ArchiSteamFarm.Steam.Interaction { default: ASF.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.WarningUnknownValuePleaseReport, nameof(result.PurchaseResultDetail), result.PurchaseResultDetail)); + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework unusedKeys.Remove(key!); // Next key diff --git a/ArchiSteamFarm/Steam/Security/MobileAuthenticator.cs b/ArchiSteamFarm/Steam/Security/MobileAuthenticator.cs index 15593afd2..881333ea5 100644 --- a/ArchiSteamFarm/Steam/Security/MobileAuthenticator.cs +++ b/ArchiSteamFarm/Steam/Security/MobileAuthenticator.cs @@ -111,8 +111,11 @@ namespace ArchiSteamFarm.Steam.Security { await LimitConfirmationsRequestsAsync().ConfigureAwait(false); + // ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework using IDocument? htmlDocument = await Bot.ArchiWebHandler.GetConfirmationsPage(deviceID!, confirmationHash!, time).ConfigureAwait(false); + // ReSharper restore RedundantSuppressNullableWarningExpression - required for .NET Framework + if (htmlDocument == null) { return null; } @@ -221,8 +224,11 @@ namespace ArchiSteamFarm.Steam.Security { return false; } + // ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework bool? result = await Bot.ArchiWebHandler.HandleConfirmations(deviceID!, confirmationHash!, time, confirmations, accept).ConfigureAwait(false); + // ReSharper restore RedundantSuppressNullableWarningExpression - required for .NET Framework + if (!result.HasValue) { // Request timed out return false; @@ -237,8 +243,11 @@ namespace ArchiSteamFarm.Steam.Security { // In this case, we'll accept all pending confirmations one-by-one, synchronously (as Steam can't handle them in parallel) // We totally ignore actual result returned by those calls, abort only if request timed out foreach (Confirmation confirmation in confirmations) { + // ReSharper disable RedundantSuppressNullableWarningExpression - required for .NET Framework bool? confirmationResult = await Bot.ArchiWebHandler.HandleConfirmation(deviceID!, confirmationHash!, time, confirmation.ID, confirmation.Key, accept).ConfigureAwait(false); + // ReSharper restore RedundantSuppressNullableWarningExpression - required for .NET Framework + if (!confirmationResult.HasValue) { return false; } @@ -287,7 +296,7 @@ namespace ArchiSteamFarm.Steam.Security { byte[] identitySecret; try { - identitySecret = Convert.FromBase64String(IdentitySecret!); + identitySecret = Convert.FromBase64String(IdentitySecret); } catch (FormatException e) { Bot.ArchiLogger.LogGenericException(e); Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(IdentitySecret))); @@ -298,6 +307,7 @@ namespace ArchiSteamFarm.Steam.Security { byte bufferSize = 8; if (!string.IsNullOrEmpty(tag)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework bufferSize += (byte) Math.Min(32, tag!.Length); } @@ -312,6 +322,7 @@ namespace ArchiSteamFarm.Steam.Security { Array.Copy(timeArray, buffer, 8); if (!string.IsNullOrEmpty(tag)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework Array.Copy(Encoding.UTF8.GetBytes(tag!), 0, buffer, 8, bufferSize - 8); } @@ -342,7 +353,7 @@ namespace ArchiSteamFarm.Steam.Security { byte[] sharedSecret; try { - sharedSecret = Convert.FromBase64String(SharedSecret!); + sharedSecret = Convert.FromBase64String(SharedSecret); } catch (FormatException e) { Bot.ArchiLogger.LogGenericException(e); Bot.ArchiLogger.LogGenericError(string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsInvalid, nameof(SharedSecret))); diff --git a/ArchiSteamFarm/Steam/SteamKit2/InMemoryServerListProvider.cs b/ArchiSteamFarm/Steam/SteamKit2/InMemoryServerListProvider.cs index 57f4897b9..5b85566c4 100644 --- a/ArchiSteamFarm/Steam/SteamKit2/InMemoryServerListProvider.cs +++ b/ArchiSteamFarm/Steam/SteamKit2/InMemoryServerListProvider.cs @@ -32,7 +32,7 @@ namespace ArchiSteamFarm.Steam.SteamKit2 { [JsonProperty(Required = Required.DisallowNull)] private readonly ConcurrentHashSet ServerRecords = new(); - public Task> FetchServerListAsync() => Task.FromResult(ServerRecords.Where(server => !string.IsNullOrEmpty(server.Host) && (server.Port > 0) && (server.ProtocolTypes > 0)).Select(server => ServerRecord.CreateServer(server.Host!, server.Port, server.ProtocolTypes))); + public Task> FetchServerListAsync() => Task.FromResult(ServerRecords.Where(server => !string.IsNullOrEmpty(server.Host) && (server.Port > 0) && (server.ProtocolTypes > 0)).Select(server => ServerRecord.CreateServer(server.Host, server.Port, server.ProtocolTypes))); public Task UpdateServerListAsync(IEnumerable endpoints) { if (endpoints == null) { diff --git a/ArchiSteamFarm/Steam/Storage/BotConfig.cs b/ArchiSteamFarm/Steam/Storage/BotConfig.cs index 5d6a5806d..f13c9f7f8 100644 --- a/ArchiSteamFarm/Steam/Storage/BotConfig.cs +++ b/ArchiSteamFarm/Steam/Storage/BotConfig.cs @@ -301,6 +301,7 @@ namespace ArchiSteamFarm.Steam.Storage { set { if (!string.IsNullOrEmpty(value) && (PasswordFormat != ArchiCryptoHelper.ECryptoMethod.PlainText)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework value = ArchiCryptoHelper.Encrypt(PasswordFormat, value!); } @@ -496,6 +497,7 @@ namespace ArchiSteamFarm.Steam.Storage { if (!valid) { if (!string.IsNullOrEmpty(errorMessage)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework ASF.ArchiLogger.LogGenericError(errorMessage!); } diff --git a/ArchiSteamFarm/Storage/GlobalConfig.cs b/ArchiSteamFarm/Storage/GlobalConfig.cs index ad20f3897..fac1f616c 100644 --- a/ArchiSteamFarm/Storage/GlobalConfig.cs +++ b/ArchiSteamFarm/Storage/GlobalConfig.cs @@ -393,6 +393,7 @@ namespace ArchiSteamFarm.Storage { if (!valid) { if (!string.IsNullOrEmpty(errorMessage)) { + // ReSharper disable once RedundantSuppressNullableWarningExpression - required for .NET Framework ASF.ArchiLogger.LogGenericError(errorMessage!); } diff --git a/ArchiSteamFarm/TrimmerRoots.xml b/ArchiSteamFarm/TrimmerRoots.xml index 12dc2cd1b..492779153 100644 --- a/ArchiSteamFarm/TrimmerRoots.xml +++ b/ArchiSteamFarm/TrimmerRoots.xml @@ -1,8 +1,8 @@ - - - - + + + + - + diff --git a/ArchiSteamFarm/overlay/all/Changelog.html b/ArchiSteamFarm/overlay/all/Changelog.html index 2933f476b..dbbd9776a 100644 --- a/ArchiSteamFarm/overlay/all/Changelog.html +++ b/ArchiSteamFarm/overlay/all/Changelog.html @@ -2,7 +2,7 @@ ASF Changelog - + diff --git a/ArchiSteamFarm/overlay/all/ConfigGenerator.html b/ArchiSteamFarm/overlay/all/ConfigGenerator.html index 25527364e..a086fe0b6 100644 --- a/ArchiSteamFarm/overlay/all/ConfigGenerator.html +++ b/ArchiSteamFarm/overlay/all/ConfigGenerator.html @@ -2,7 +2,7 @@ ASF Config Generator - + diff --git a/ArchiSteamFarm/overlay/all/Manual.html b/ArchiSteamFarm/overlay/all/Manual.html index d3b227c62..0f01cd7b2 100644 --- a/ArchiSteamFarm/overlay/all/Manual.html +++ b/ArchiSteamFarm/overlay/all/Manual.html @@ -2,7 +2,7 @@ ASF Manual - + diff --git a/ArchiSteamFarm/overlay/all/UI.html b/ArchiSteamFarm/overlay/all/UI.html index 1f00df65e..a586eac33 100644 --- a/ArchiSteamFarm/overlay/all/UI.html +++ b/ArchiSteamFarm/overlay/all/UI.html @@ -2,7 +2,7 @@ ASF UI - + diff --git a/Directory.Build.props b/Directory.Build.props index bbb766086..8a8e93648 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,59 +1,59 @@ - - 5.1.2.2 - + + 5.1.2.2 + - - AllEnabledByDefault - ../resources/ASF.ico - JustArchi - JustArchiNET - Copyright © 2015-2021 JustArchiNET - ASF is a C# application with primary purpose of idling Steam cards from multiple accounts simultaneously. - true - none - latest - true - en - 1591 - enable - ../resources/ASF.ico - Apache-2.0 - https://github.com/JustArchiNET/ArchiSteamFarm - Git - https://github.com/JustArchiNET/ArchiSteamFarm.git - LatestMajor - linux-arm;linux-arm64;linux-x64;osx-x64;win-x64 - true - + + AllEnabledByDefault + ../resources/ASF.ico + JustArchi + JustArchiNET + Copyright © 2015-2021 JustArchiNET + ASF is a C# application with primary purpose of idling Steam cards from multiple accounts simultaneously. + true + none + latest + true + en + 1591 + enable + ../resources/ASF.ico + Apache-2.0 + https://github.com/JustArchiNET/ArchiSteamFarm + Git + https://github.com/JustArchiNET/ArchiSteamFarm.git + LatestMajor + linux-arm;linux-arm64;linux-x64;osx-x64;win-x64 + true + - - $(DefineConstants);ASF_VARIANT_$(ASFVariant.Replace('-', '_').ToUpperInvariant()) - + + $(DefineConstants);ASF_VARIANT_$(ASFVariant.Replace('-', '_').ToUpperInvariant()) + - - - false - none - true - - + + + false + none + true + + - - - false - false - false - false - false - link - + + + false + false + false + false + false + link + - - net5.0;net48 - + + net5.0;net48 + - - net5.0 - + + net5.0 +