2019-02-16 17:34:17 +01:00
|
|
|
// _ _ _ ____ _ _____
|
2017-11-18 17:27:06 +01:00
|
|
|
// / \ _ __ ___ | |__ (_)/ ___| | |_ ___ __ _ _ __ ___ | ___|__ _ _ __ _ __ ___
|
|
|
|
|
// / _ \ | '__|/ __|| '_ \ | |\___ \ | __|/ _ \ / _` || '_ ` _ \ | |_ / _` || '__|| '_ ` _ \
|
|
|
|
|
// / ___ \ | | | (__ | | | || | ___) || |_| __/| (_| || | | | | || _|| (_| || | | | | | | |
|
|
|
|
|
// /_/ \_\|_| \___||_| |_||_||____/ \__|\___| \__,_||_| |_| |_||_| \__,_||_| |_| |_| |_|
|
2019-01-14 19:11:17 +01:00
|
|
|
// |
|
2020-02-01 23:33:35 +01:00
|
|
|
// Copyright 2015-2020 Łukasz "JustArchi" Domeradzki
|
2018-07-27 04:52:14 +02:00
|
|
|
// Contact: JustArchi@JustArchi.net
|
2019-01-14 19:11:17 +01:00
|
|
|
// |
|
2018-07-27 04:52:14 +02:00
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
2019-01-14 19:11:17 +01:00
|
|
|
// |
|
2018-07-27 04:52:14 +02:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2019-01-14 19:11:17 +01:00
|
|
|
// |
|
2018-07-27 04:52:14 +02:00
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
2016-03-06 02:20:41 +01:00
|
|
|
|
|
|
|
|
using System;
|
2019-01-10 22:33:07 +01:00
|
|
|
using System.Collections.Generic;
|
2018-08-06 01:21:36 +02:00
|
|
|
using System.Collections.Immutable;
|
2019-10-13 17:21:40 +02:00
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2016-03-06 02:20:41 +01:00
|
|
|
using System.IO;
|
2018-08-06 01:21:36 +02:00
|
|
|
using System.Linq;
|
2017-12-06 08:14:12 +01:00
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2017-12-14 08:23:17 +01:00
|
|
|
using ArchiSteamFarm.Json;
|
2017-01-06 16:29:34 +01:00
|
|
|
using ArchiSteamFarm.Localization;
|
2019-01-10 22:33:07 +01:00
|
|
|
using JetBrains.Annotations;
|
2016-11-24 07:32:16 +01:00
|
|
|
using Newtonsoft.Json;
|
2019-01-10 22:33:07 +01:00
|
|
|
using Newtonsoft.Json.Linq;
|
2018-06-13 00:48:33 +02:00
|
|
|
using SteamKit2;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
|
|
|
|
namespace ArchiSteamFarm {
|
2019-10-13 17:21:40 +02:00
|
|
|
[SuppressMessage("ReSharper", "ClassCannotBeInstantiated")]
|
2018-10-06 05:06:29 +02:00
|
|
|
public sealed class BotConfig {
|
2019-07-20 02:56:14 +02:00
|
|
|
internal const byte SteamParentalCodeLength = 4;
|
|
|
|
|
|
2018-08-06 01:21:36 +02:00
|
|
|
private const bool DefaultAcceptGifts = false;
|
|
|
|
|
private const bool DefaultAutoSteamSaleEvent = false;
|
|
|
|
|
private const EBotBehaviour DefaultBotBehaviour = EBotBehaviour.None;
|
|
|
|
|
private const string DefaultCustomGamePlayedWhileFarming = null;
|
|
|
|
|
private const string DefaultCustomGamePlayedWhileIdle = null;
|
|
|
|
|
private const bool DefaultEnabled = false;
|
|
|
|
|
private const byte DefaultHoursUntilCardDrops = 3;
|
|
|
|
|
private const bool DefaultIdlePriorityQueueOnly = false;
|
|
|
|
|
private const bool DefaultIdleRefundableGames = true;
|
|
|
|
|
private const EPersonaState DefaultOnlineStatus = EPersonaState.Online;
|
2018-08-19 14:37:23 +02:00
|
|
|
private const ArchiCryptoHelper.ECryptoMethod DefaultPasswordFormat = ArchiCryptoHelper.ECryptoMethod.PlainText;
|
2018-08-06 01:21:36 +02:00
|
|
|
private const bool DefaultPaused = false;
|
|
|
|
|
private const ERedeemingPreferences DefaultRedeemingPreferences = ERedeemingPreferences.None;
|
|
|
|
|
private const bool DefaultSendOnFarmingFinished = false;
|
|
|
|
|
private const byte DefaultSendTradePeriod = 0;
|
|
|
|
|
private const bool DefaultShutdownOnFarmingFinished = false;
|
|
|
|
|
private const string DefaultSteamLogin = null;
|
|
|
|
|
private const ulong DefaultSteamMasterClanID = 0;
|
2018-09-22 15:50:11 +02:00
|
|
|
private const string DefaultSteamParentalCode = null;
|
2018-09-18 19:58:17 +02:00
|
|
|
private const string DefaultSteamPassword = null;
|
2018-08-06 01:21:36 +02:00
|
|
|
private const string DefaultSteamTradeToken = null;
|
|
|
|
|
private const ETradingPreferences DefaultTradingPreferences = ETradingPreferences.None;
|
|
|
|
|
private const bool DefaultUseLoginKeys = true;
|
|
|
|
|
|
2018-09-18 21:23:04 +02:00
|
|
|
private static readonly ImmutableList<EFarmingOrder> DefaultFarmingOrders = ImmutableList<EFarmingOrder>.Empty;
|
2018-08-06 01:21:36 +02:00
|
|
|
private static readonly ImmutableHashSet<uint> DefaultGamesPlayedWhileIdle = ImmutableHashSet<uint>.Empty;
|
|
|
|
|
private static readonly ImmutableHashSet<Steam.Asset.EType> DefaultLootableTypes = ImmutableHashSet.Create(Steam.Asset.EType.BoosterPack, Steam.Asset.EType.FoilTradingCard, Steam.Asset.EType.TradingCard);
|
|
|
|
|
private static readonly ImmutableHashSet<Steam.Asset.EType> DefaultMatchableTypes = ImmutableHashSet.Create(Steam.Asset.EType.TradingCard);
|
|
|
|
|
private static readonly ImmutableDictionary<ulong, EPermission> DefaultSteamUserPermissions = ImmutableDictionary<ulong, EPermission>.Empty;
|
2018-10-06 02:24:04 +02:00
|
|
|
private static readonly ImmutableHashSet<Steam.Asset.EType> DefaultTransferableTypes = ImmutableHashSet.Create(Steam.Asset.EType.BoosterPack, Steam.Asset.EType.FoilTradingCard, Steam.Asset.EType.TradingCard);
|
2018-08-06 01:21:36 +02:00
|
|
|
|
2017-12-06 08:14:12 +01:00
|
|
|
private static readonly SemaphoreSlim WriteSemaphore = new SemaphoreSlim(1, 1);
|
|
|
|
|
|
2016-03-06 02:20:41 +01:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly bool AcceptGifts = DefaultAcceptGifts;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
2017-07-23 01:34:02 +02:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly bool AutoSteamSaleEvent = DefaultAutoSteamSaleEvent;
|
2017-07-23 01:34:02 +02:00
|
|
|
|
2018-07-14 16:29:33 +02:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly EBotBehaviour BotBehaviour = DefaultBotBehaviour;
|
2018-07-14 16:29:33 +02:00
|
|
|
|
2016-03-06 02:20:41 +01:00
|
|
|
[JsonProperty]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly string CustomGamePlayedWhileFarming = DefaultCustomGamePlayedWhileFarming;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
|
|
|
|
[JsonProperty]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly string CustomGamePlayedWhileIdle = DefaultCustomGamePlayedWhileIdle;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
|
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly bool Enabled = DefaultEnabled;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
2018-08-06 01:21:36 +02:00
|
|
|
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly ImmutableList<EFarmingOrder> FarmingOrders = DefaultFarmingOrders;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
2018-08-06 01:21:36 +02:00
|
|
|
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly ImmutableHashSet<uint> GamesPlayedWhileIdle = DefaultGamesPlayedWhileIdle;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
2017-10-15 11:15:36 +02:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly byte HoursUntilCardDrops = DefaultHoursUntilCardDrops;
|
2017-10-15 11:15:36 +02:00
|
|
|
|
2017-07-23 10:27:20 +02:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly bool IdlePriorityQueueOnly = DefaultIdlePriorityQueueOnly;
|
2018-02-28 02:14:29 +01:00
|
|
|
|
|
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly bool IdleRefundableGames = DefaultIdleRefundableGames;
|
2017-07-23 10:27:20 +02:00
|
|
|
|
2016-12-30 13:01:02 +01:00
|
|
|
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly ImmutableHashSet<Steam.Asset.EType> LootableTypes = DefaultLootableTypes;
|
2016-12-25 05:52:17 +01:00
|
|
|
|
2017-07-10 08:20:15 +02:00
|
|
|
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly ImmutableHashSet<Steam.Asset.EType> MatchableTypes = DefaultMatchableTypes;
|
2017-07-10 08:20:15 +02:00
|
|
|
|
2018-07-04 19:13:51 +02:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly EPersonaState OnlineStatus = DefaultOnlineStatus;
|
2018-07-04 19:13:51 +02:00
|
|
|
|
2016-06-04 22:02:38 +02:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly ArchiCryptoHelper.ECryptoMethod PasswordFormat = DefaultPasswordFormat;
|
2016-06-04 22:02:38 +02:00
|
|
|
|
2016-03-06 02:20:41 +01:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly bool Paused = DefaultPaused;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
2016-12-25 06:29:13 +01:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly ERedeemingPreferences RedeemingPreferences = DefaultRedeemingPreferences;
|
2016-12-25 06:29:13 +01:00
|
|
|
|
2016-03-06 02:20:41 +01:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly bool SendOnFarmingFinished = DefaultSendOnFarmingFinished;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
|
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly byte SendTradePeriod = DefaultSendTradePeriod;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
|
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly bool ShutdownOnFarmingFinished = DefaultShutdownOnFarmingFinished;
|
2016-03-06 02:20:41 +01:00
|
|
|
|
2016-11-24 07:32:16 +01:00
|
|
|
[JsonProperty]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly string SteamTradeToken = DefaultSteamTradeToken;
|
2016-10-21 20:32:22 +02:00
|
|
|
|
2018-08-06 01:21:36 +02:00
|
|
|
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly ImmutableDictionary<ulong, EPermission> SteamUserPermissions = DefaultSteamUserPermissions;
|
2017-03-15 11:56:20 +01:00
|
|
|
|
2016-10-21 20:32:22 +02:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly ETradingPreferences TradingPreferences = DefaultTradingPreferences;
|
2016-03-10 21:17:48 +01:00
|
|
|
|
2018-10-06 02:24:04 +02:00
|
|
|
[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace, Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly ImmutableHashSet<Steam.Asset.EType> TransferableTypes = DefaultTransferableTypes;
|
2018-10-06 02:24:04 +02:00
|
|
|
|
2017-11-28 21:31:45 +01:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
2019-01-14 21:50:23 +01:00
|
|
|
public readonly bool UseLoginKeys = DefaultUseLoginKeys;
|
2018-08-06 01:21:36 +02:00
|
|
|
|
2019-01-17 16:37:16 +01:00
|
|
|
[JsonProperty(Required = Required.DisallowNull)]
|
|
|
|
|
public ulong SteamMasterClanID { get; private set; } = DefaultSteamMasterClanID;
|
|
|
|
|
|
2019-01-10 22:33:07 +01:00
|
|
|
[JsonExtensionData]
|
2020-03-06 11:30:53 +01:00
|
|
|
internal Dictionary<string, JToken> AdditionalProperties {
|
|
|
|
|
get;
|
|
|
|
|
[UsedImplicitly]
|
|
|
|
|
set;
|
|
|
|
|
}
|
2019-01-10 22:33:07 +01:00
|
|
|
|
2018-09-22 15:50:11 +02:00
|
|
|
internal string DecryptedSteamPassword {
|
2018-09-18 19:58:17 +02:00
|
|
|
get {
|
|
|
|
|
if (string.IsNullOrEmpty(SteamPassword)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2017-07-01 13:39:53 +02:00
|
|
|
|
2018-09-18 19:58:17 +02:00
|
|
|
if (PasswordFormat == ArchiCryptoHelper.ECryptoMethod.PlainText) {
|
|
|
|
|
return SteamPassword;
|
|
|
|
|
}
|
2016-03-08 03:18:50 +01:00
|
|
|
|
2019-03-23 16:16:57 +01:00
|
|
|
string result = ArchiCryptoHelper.Decrypt(PasswordFormat, SteamPassword);
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2019-03-23 16:16:57 +01:00
|
|
|
if (string.IsNullOrEmpty(result)) {
|
2018-09-18 19:58:17 +02:00
|
|
|
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(SteamPassword)));
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2018-08-18 19:26:18 +02:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-23 16:16:57 +01:00
|
|
|
return result;
|
2018-08-18 19:26:18 +02:00
|
|
|
}
|
2019-07-25 17:09:20 +02:00
|
|
|
|
2018-08-18 19:26:18 +02:00
|
|
|
set {
|
2019-03-23 16:16:57 +01:00
|
|
|
if (!string.IsNullOrEmpty(value) && (PasswordFormat != ArchiCryptoHelper.ECryptoMethod.PlainText)) {
|
|
|
|
|
value = ArchiCryptoHelper.Encrypt(PasswordFormat, value);
|
2018-08-18 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-23 16:16:57 +01:00
|
|
|
SteamPassword = value;
|
2018-08-18 19:26:18 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-22 15:50:11 +02:00
|
|
|
internal bool IsSteamLoginSet { get; private set; }
|
|
|
|
|
internal bool IsSteamParentalCodeSet { get; private set; }
|
|
|
|
|
internal bool IsSteamPasswordSet { get; private set; }
|
2020-06-25 14:05:39 +02:00
|
|
|
internal bool ShouldSerializeDefaultValues { private get; set; } = true;
|
2018-10-16 00:15:48 +02:00
|
|
|
internal bool ShouldSerializeHelperProperties { private get; set; } = true;
|
2020-06-25 14:05:39 +02:00
|
|
|
internal bool ShouldSerializeSensitiveDetails { private get; set; }
|
2018-09-18 19:58:17 +02:00
|
|
|
|
|
|
|
|
[JsonProperty]
|
2018-09-22 15:50:11 +02:00
|
|
|
internal string SteamLogin {
|
2019-07-25 17:09:20 +02:00
|
|
|
get => BackingSteamLogin;
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2018-09-22 15:50:11 +02:00
|
|
|
set {
|
|
|
|
|
IsSteamLoginSet = true;
|
2019-07-25 17:09:20 +02:00
|
|
|
BackingSteamLogin = value;
|
2018-09-22 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-09-18 19:58:17 +02:00
|
|
|
|
|
|
|
|
[JsonProperty]
|
2018-09-22 15:50:11 +02:00
|
|
|
internal string SteamParentalCode {
|
2019-07-25 17:09:20 +02:00
|
|
|
get => BackingSteamParentalCode;
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2018-09-22 15:50:11 +02:00
|
|
|
set {
|
|
|
|
|
IsSteamParentalCodeSet = true;
|
2019-07-25 17:09:20 +02:00
|
|
|
BackingSteamParentalCode = value;
|
2018-09-22 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-12-10 01:08:01 +01:00
|
|
|
|
2018-09-18 19:58:17 +02:00
|
|
|
[JsonProperty]
|
2018-09-22 15:50:11 +02:00
|
|
|
internal string SteamPassword {
|
2019-07-25 17:09:20 +02:00
|
|
|
get => BackingSteamPassword;
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2018-09-22 15:50:11 +02:00
|
|
|
set {
|
|
|
|
|
IsSteamPasswordSet = true;
|
2019-07-25 17:09:20 +02:00
|
|
|
BackingSteamPassword = value;
|
2018-09-22 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-25 17:09:20 +02:00
|
|
|
private string BackingSteamLogin = DefaultSteamLogin;
|
|
|
|
|
private string BackingSteamParentalCode = DefaultSteamParentalCode;
|
|
|
|
|
private string BackingSteamPassword = DefaultSteamPassword;
|
2018-09-18 19:58:17 +02:00
|
|
|
|
2018-02-11 11:11:38 +01:00
|
|
|
[JsonProperty(PropertyName = SharedInfo.UlongCompatibilityStringPrefix + nameof(SteamMasterClanID), Required = Required.DisallowNull)]
|
2019-10-13 17:21:40 +02:00
|
|
|
[JetBrains.Annotations.NotNull]
|
2018-02-11 09:58:25 +01:00
|
|
|
private string SSteamMasterClanID {
|
|
|
|
|
get => SteamMasterClanID.ToString();
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2018-02-11 09:58:25 +01:00
|
|
|
set {
|
|
|
|
|
if (string.IsNullOrEmpty(value) || !ulong.TryParse(value, out ulong result)) {
|
|
|
|
|
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, nameof(SSteamMasterClanID)));
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2018-02-11 09:58:25 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SteamMasterClanID = result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-14 21:50:23 +01:00
|
|
|
[JsonConstructor]
|
|
|
|
|
private BotConfig() { }
|
|
|
|
|
|
2018-09-22 15:50:11 +02:00
|
|
|
internal (bool Valid, string ErrorMessage) CheckValidation() {
|
|
|
|
|
if (BotBehaviour > EBotBehaviour.All) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(BotBehaviour), BotBehaviour));
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-10 17:38:49 +02:00
|
|
|
foreach (EFarmingOrder farmingOrder in FarmingOrders.Where(farmingOrder => !Enum.IsDefined(typeof(EFarmingOrder), farmingOrder))) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(FarmingOrders), farmingOrder));
|
2018-09-22 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GamesPlayedWhileIdle.Count > ArchiHandler.MaxGamesPlayedConcurrently) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(GamesPlayedWhileIdle), GamesPlayedWhileIdle.Count + " > " + ArchiHandler.MaxGamesPlayedConcurrently));
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-10 17:38:49 +02:00
|
|
|
foreach (Steam.Asset.EType lootableType in LootableTypes.Where(lootableType => !Enum.IsDefined(typeof(Steam.Asset.EType), lootableType))) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(LootableTypes), lootableType));
|
2018-09-22 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-10 17:38:49 +02:00
|
|
|
foreach (Steam.Asset.EType matchableType in MatchableTypes.Where(matchableType => !Enum.IsDefined(typeof(Steam.Asset.EType), matchableType))) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(MatchableTypes), matchableType));
|
2018-09-22 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
2020-06-06 16:00:05 +03:00
|
|
|
if (!Enum.IsDefined(typeof(EPersonaState), OnlineStatus)) {
|
2018-09-22 15:50:11 +02:00
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(OnlineStatus), OnlineStatus));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Enum.IsDefined(typeof(ArchiCryptoHelper.ECryptoMethod), PasswordFormat)) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(PasswordFormat), PasswordFormat));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (RedeemingPreferences > ERedeemingPreferences.All) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(RedeemingPreferences), RedeemingPreferences));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((SteamMasterClanID != 0) && !new SteamID(SteamMasterClanID).IsClanAccount) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamMasterClanID), SteamMasterClanID));
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-20 02:56:14 +02:00
|
|
|
if (!string.IsNullOrEmpty(SteamParentalCode) && (SteamParentalCode != "0") && (SteamParentalCode.Length != SteamParentalCodeLength)) {
|
2018-09-22 15:50:11 +02:00
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamParentalCode), SteamParentalCode));
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-01 22:41:25 +01:00
|
|
|
foreach ((ulong steamID, EPermission permission) in SteamUserPermissions) {
|
|
|
|
|
if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamUserPermissions), steamID));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Enum.IsDefined(typeof(EPermission), permission)) {
|
|
|
|
|
return (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(SteamUserPermissions), permission));
|
|
|
|
|
}
|
2018-09-22 15:50:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TradingPreferences <= ETradingPreferences.All ? (true, null) : (false, string.Format(Strings.ErrorConfigPropertyInvalid, nameof(TradingPreferences), TradingPreferences));
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-10 23:44:32 +01:00
|
|
|
[ItemCanBeNull]
|
2018-05-13 19:19:27 +02:00
|
|
|
internal static async Task<BotConfig> Load(string filePath) {
|
2016-05-30 01:57:06 +02:00
|
|
|
if (string.IsNullOrEmpty(filePath)) {
|
2017-01-31 01:10:01 +01:00
|
|
|
ASF.ArchiLogger.LogNullError(nameof(filePath));
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2016-05-30 01:57:06 +02:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!File.Exists(filePath)) {
|
2016-03-06 02:20:41 +01:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BotConfig botConfig;
|
2016-05-30 01:57:06 +02:00
|
|
|
|
2016-03-06 02:20:41 +01:00
|
|
|
try {
|
2019-04-04 22:34:58 +02:00
|
|
|
string json = await RuntimeCompatibility.File.ReadAllTextAsync(filePath).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(json)) {
|
|
|
|
|
ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsEmpty, nameof(json)));
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
botConfig = JsonConvert.DeserializeObject<BotConfig>(json);
|
2016-03-06 02:20:41 +01:00
|
|
|
} catch (Exception e) {
|
2017-01-31 01:10:01 +01:00
|
|
|
ASF.ArchiLogger.LogGenericException(e);
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2016-03-06 02:20:41 +01:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-31 17:38:14 +02:00
|
|
|
if (botConfig == null) {
|
2017-01-31 01:10:01 +01:00
|
|
|
ASF.ArchiLogger.LogNullError(nameof(botConfig));
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2016-07-31 17:38:14 +02:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-18 21:23:04 +02:00
|
|
|
(bool valid, string errorMessage) = botConfig.CheckValidation();
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2018-09-18 21:23:04 +02:00
|
|
|
if (!valid) {
|
|
|
|
|
ASF.ArchiLogger.LogGenericError(errorMessage);
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2018-07-04 19:13:51 +02:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-06 02:20:41 +01:00
|
|
|
return botConfig;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-06 08:14:12 +01:00
|
|
|
internal static async Task<bool> Write(string filePath, BotConfig botConfig) {
|
|
|
|
|
if (string.IsNullOrEmpty(filePath) || (botConfig == null)) {
|
|
|
|
|
ASF.ArchiLogger.LogNullError(nameof(filePath) + " || " + nameof(botConfig));
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2017-12-06 08:14:12 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string json = JsonConvert.SerializeObject(botConfig, Formatting.Indented);
|
|
|
|
|
string newFilePath = filePath + ".new";
|
|
|
|
|
|
|
|
|
|
await WriteSemaphore.WaitAsync().ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
try {
|
2018-06-03 07:51:20 +02:00
|
|
|
await RuntimeCompatibility.File.WriteAllTextAsync(newFilePath, json).ConfigureAwait(false);
|
2017-12-06 08:14:12 +01:00
|
|
|
|
|
|
|
|
if (File.Exists(filePath)) {
|
|
|
|
|
File.Replace(newFilePath, filePath, null);
|
|
|
|
|
} else {
|
|
|
|
|
File.Move(newFilePath, filePath);
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
ASF.ArchiLogger.LogGenericException(e);
|
2018-12-15 00:27:15 +01:00
|
|
|
|
2017-12-06 08:14:12 +01:00
|
|
|
return false;
|
|
|
|
|
} finally {
|
|
|
|
|
WriteSemaphore.Release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-23 23:51:34 +02:00
|
|
|
[Flags]
|
2019-01-14 21:50:23 +01:00
|
|
|
public enum EBotBehaviour : byte {
|
2018-04-23 23:51:34 +02:00
|
|
|
None = 0,
|
|
|
|
|
RejectInvalidFriendInvites = 1,
|
2018-05-02 02:39:41 +02:00
|
|
|
RejectInvalidTrades = 2,
|
2018-06-19 20:02:11 +02:00
|
|
|
RejectInvalidGroupInvites = 4,
|
2018-07-04 19:13:51 +02:00
|
|
|
DismissInventoryNotifications = 8,
|
2018-07-24 23:43:25 +02:00
|
|
|
MarkReceivedMessagesAsRead = 16,
|
2019-11-06 19:42:23 +02:00
|
|
|
MarkBotMessagesAsRead = 32,
|
2019-11-06 20:25:32 +01:00
|
|
|
All = RejectInvalidFriendInvites | RejectInvalidTrades | RejectInvalidGroupInvites | DismissInventoryNotifications | MarkReceivedMessagesAsRead | MarkBotMessagesAsRead
|
2018-04-23 23:51:34 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-14 21:50:23 +01:00
|
|
|
public enum EFarmingOrder : byte {
|
2016-11-24 07:32:16 +01:00
|
|
|
Unordered,
|
|
|
|
|
AppIDsAscending,
|
|
|
|
|
AppIDsDescending,
|
|
|
|
|
CardDropsAscending,
|
|
|
|
|
CardDropsDescending,
|
|
|
|
|
HoursAscending,
|
|
|
|
|
HoursDescending,
|
|
|
|
|
NamesAscending,
|
2017-07-02 10:00:02 +02:00
|
|
|
NamesDescending,
|
2017-07-23 05:06:11 +02:00
|
|
|
Random,
|
|
|
|
|
BadgeLevelsAscending,
|
2017-07-23 11:55:44 +02:00
|
|
|
BadgeLevelsDescending,
|
|
|
|
|
RedeemDateTimesAscending,
|
2018-07-04 19:13:51 +02:00
|
|
|
RedeemDateTimesDescending,
|
|
|
|
|
MarketableAscending,
|
|
|
|
|
MarketableDescending
|
2016-11-24 07:32:16 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-14 21:50:23 +01:00
|
|
|
public enum EPermission : byte {
|
|
|
|
|
None,
|
|
|
|
|
FamilySharing,
|
|
|
|
|
Operator,
|
|
|
|
|
Master
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-25 06:29:13 +01:00
|
|
|
[Flags]
|
2019-01-14 21:50:23 +01:00
|
|
|
public enum ERedeemingPreferences : byte {
|
2016-12-25 06:29:13 +01:00
|
|
|
None = 0,
|
|
|
|
|
Forwarding = 1,
|
2017-02-18 01:03:13 +01:00
|
|
|
Distributing = 2,
|
2018-07-04 19:13:51 +02:00
|
|
|
KeepMissingGames = 4,
|
2019-08-05 15:41:37 +03:00
|
|
|
AssumeWalletKeyOnBadActivationCode = 8,
|
|
|
|
|
All = Forwarding | Distributing | KeepMissingGames | AssumeWalletKeyOnBadActivationCode
|
2016-12-25 06:29:13 +01:00
|
|
|
}
|
|
|
|
|
|
2016-11-24 07:32:16 +01:00
|
|
|
[Flags]
|
2019-01-14 21:50:23 +01:00
|
|
|
public enum ETradingPreferences : byte {
|
2016-11-24 07:32:16 +01:00
|
|
|
None = 0,
|
|
|
|
|
AcceptDonations = 1,
|
|
|
|
|
SteamTradeMatcher = 2,
|
2017-02-05 07:51:04 +01:00
|
|
|
MatchEverything = 4,
|
2018-07-04 19:13:51 +02:00
|
|
|
DontAcceptBotTrades = 8,
|
Implement ETradingPreferences.MatchActively
This will probably need a lot more tests, tweaking and bugfixing, but basic logic is:
- MatchActively added to TradingPreferences with value of 16
- User must also use SteamTradeMatcher, can't use MatchEverything
- User must have statistics enabled and be eligible for being listed (no requirement of having 100 items minimum)
Once all requirements are passed, statistics module will communicate with the listing and fetch match everything bots:
- The matching will start in 1h since ASF start and will repeat every day (right now it starts in 1 minute to aid debugging).
- Each matching is composed of up to 10 rounds maximum.
- In each round ASF will fetch our inventory and inventory of listed bots in order to find MatchableTypes items to be matched. If match is found, offer is being sent and confirmed automatically.
- Each set (composition of item type + appID it's from) can be matched in a single round only once, this is to minimize "items no longer available" as much as possible and also avoid a need to wait for each bot to react before sending all trades.
- Round ends when we try to match a total of 20 bots, or we hit no items to match in consecutive 10 tries with 10 different bots.
- If last round resulted in at least a single trade being sent, next round starts within 5 minutes since last one, otherwise matching ends and repeats the next day.
We'll see how it works in practice, expect a lot of follow-up commits, unless I won't have anything to fix or improve.
2018-11-29 18:35:58 +01:00
|
|
|
MatchActively = 16,
|
|
|
|
|
All = AcceptDonations | SteamTradeMatcher | MatchEverything | DontAcceptBotTrades | MatchActively
|
2016-11-24 07:32:16 +01:00
|
|
|
}
|
2018-08-06 01:21:36 +02:00
|
|
|
|
|
|
|
|
// ReSharper disable UnusedMember.Global
|
2020-06-25 14:05:39 +02:00
|
|
|
public bool ShouldSerializeAcceptGifts() => ShouldSerializeDefaultValues || (AcceptGifts != DefaultAcceptGifts);
|
|
|
|
|
public bool ShouldSerializeAutoSteamSaleEvent() => ShouldSerializeDefaultValues || (AutoSteamSaleEvent != DefaultAutoSteamSaleEvent);
|
|
|
|
|
public bool ShouldSerializeBotBehaviour() => ShouldSerializeDefaultValues || (BotBehaviour != DefaultBotBehaviour);
|
|
|
|
|
public bool ShouldSerializeCustomGamePlayedWhileFarming() => ShouldSerializeDefaultValues || (CustomGamePlayedWhileFarming != DefaultCustomGamePlayedWhileFarming);
|
|
|
|
|
public bool ShouldSerializeCustomGamePlayedWhileIdle() => ShouldSerializeDefaultValues || (CustomGamePlayedWhileIdle != DefaultCustomGamePlayedWhileIdle);
|
|
|
|
|
public bool ShouldSerializeEnabled() => ShouldSerializeDefaultValues || (Enabled != DefaultEnabled);
|
|
|
|
|
public bool ShouldSerializeFarmingOrders() => ShouldSerializeDefaultValues || ((FarmingOrders != DefaultFarmingOrders) && !FarmingOrders.SequenceEqual(DefaultFarmingOrders));
|
|
|
|
|
public bool ShouldSerializeGamesPlayedWhileIdle() => ShouldSerializeDefaultValues || ((GamesPlayedWhileIdle != DefaultGamesPlayedWhileIdle) && !GamesPlayedWhileIdle.SetEquals(DefaultGamesPlayedWhileIdle));
|
|
|
|
|
public bool ShouldSerializeHoursUntilCardDrops() => ShouldSerializeDefaultValues || (HoursUntilCardDrops != DefaultHoursUntilCardDrops);
|
|
|
|
|
public bool ShouldSerializeIdlePriorityQueueOnly() => ShouldSerializeDefaultValues || (IdlePriorityQueueOnly != DefaultIdlePriorityQueueOnly);
|
|
|
|
|
public bool ShouldSerializeIdleRefundableGames() => ShouldSerializeDefaultValues || (IdleRefundableGames != DefaultIdleRefundableGames);
|
|
|
|
|
public bool ShouldSerializeLootableTypes() => ShouldSerializeDefaultValues || ((LootableTypes != DefaultLootableTypes) && !LootableTypes.SetEquals(DefaultLootableTypes));
|
|
|
|
|
public bool ShouldSerializeMatchableTypes() => ShouldSerializeDefaultValues || ((MatchableTypes != DefaultMatchableTypes) && !MatchableTypes.SetEquals(DefaultMatchableTypes));
|
|
|
|
|
public bool ShouldSerializeOnlineStatus() => ShouldSerializeDefaultValues || (OnlineStatus != DefaultOnlineStatus);
|
|
|
|
|
public bool ShouldSerializePasswordFormat() => ShouldSerializeDefaultValues || (PasswordFormat != DefaultPasswordFormat);
|
|
|
|
|
public bool ShouldSerializePaused() => ShouldSerializeDefaultValues || (Paused != DefaultPaused);
|
|
|
|
|
public bool ShouldSerializeRedeemingPreferences() => ShouldSerializeDefaultValues || (RedeemingPreferences != DefaultRedeemingPreferences);
|
|
|
|
|
public bool ShouldSerializeSendOnFarmingFinished() => ShouldSerializeDefaultValues || (SendOnFarmingFinished != DefaultSendOnFarmingFinished);
|
|
|
|
|
public bool ShouldSerializeSendTradePeriod() => ShouldSerializeDefaultValues || (SendTradePeriod != DefaultSendTradePeriod);
|
|
|
|
|
public bool ShouldSerializeShutdownOnFarmingFinished() => ShouldSerializeDefaultValues || (ShutdownOnFarmingFinished != DefaultShutdownOnFarmingFinished);
|
|
|
|
|
public bool ShouldSerializeSSteamMasterClanID() => ShouldSerializeDefaultValues || (ShouldSerializeHelperProperties && (SteamMasterClanID != DefaultSteamMasterClanID));
|
|
|
|
|
public bool ShouldSerializeSteamLogin() => ShouldSerializeSensitiveDetails && (ShouldSerializeDefaultValues || (SteamLogin != DefaultSteamLogin));
|
|
|
|
|
public bool ShouldSerializeSteamMasterClanID() => ShouldSerializeDefaultValues || (SteamMasterClanID != DefaultSteamMasterClanID);
|
|
|
|
|
public bool ShouldSerializeSteamParentalCode() => ShouldSerializeSensitiveDetails && (ShouldSerializeDefaultValues || (SteamParentalCode != DefaultSteamParentalCode));
|
|
|
|
|
public bool ShouldSerializeSteamPassword() => ShouldSerializeSensitiveDetails && (ShouldSerializeDefaultValues || (SteamPassword != DefaultSteamPassword));
|
|
|
|
|
public bool ShouldSerializeSteamTradeToken() => ShouldSerializeDefaultValues || (SteamTradeToken != DefaultSteamTradeToken);
|
|
|
|
|
public bool ShouldSerializeSteamUserPermissions() => ShouldSerializeDefaultValues || ((SteamUserPermissions != DefaultSteamUserPermissions) && ((SteamUserPermissions.Count != DefaultSteamUserPermissions.Count) || SteamUserPermissions.Except(DefaultSteamUserPermissions).Any()));
|
|
|
|
|
public bool ShouldSerializeTradingPreferences() => ShouldSerializeDefaultValues || (TradingPreferences != DefaultTradingPreferences);
|
|
|
|
|
public bool ShouldSerializeTransferableTypes() => ShouldSerializeDefaultValues || ((TransferableTypes != DefaultTransferableTypes) && !TransferableTypes.SetEquals(DefaultTransferableTypes));
|
|
|
|
|
public bool ShouldSerializeUseLoginKeys() => ShouldSerializeDefaultValues || (UseLoginKeys != DefaultUseLoginKeys);
|
2018-08-06 01:21:36 +02:00
|
|
|
|
|
|
|
|
// ReSharper restore UnusedMember.Global
|
2016-03-06 02:20:41 +01:00
|
|
|
}
|
2018-08-06 01:21:36 +02:00
|
|
|
}
|