Take command

This commit is contained in:
Harry Strongburg
2018-01-07 23:02:49 +01:00
parent cb8f1990d2
commit 05d33f831e
2 changed files with 329 additions and 0 deletions

View File

@@ -589,6 +589,113 @@ namespace ArchiSteamFarm {
}
}
[SuppressMessage("ReSharper", "FunctionComplexityOverflow")]
internal async Task<HashSet<Steam.Asset>> GetMyCommunityInventory(bool tradableOnly = false, string appId = null, string contextId = null, IReadOnlyCollection<uint> wantedRealAppIDs = null) {
if (!await RefreshSessionIfNeeded().ConfigureAwait(false)) {
return null;
}
HashSet<Steam.Asset> result = new HashSet<Steam.Asset>();
// 5000 is maximum allowed count per single request
string request = SteamCommunityURL + "/inventory/" + SteamID + "/" + appId + "/" + contextId + "?l=english&count=5000";
ulong startAssetID = 0;
await InventorySemaphore.WaitAsync().ConfigureAwait(false);
try {
while (true) {
Steam.InventoryResponse response = await WebBrowser.UrlGetToJsonResultRetry<Steam.InventoryResponse>(request + (startAssetID > 0 ? "&start_assetid=" + startAssetID : "")).ConfigureAwait(false);
if (response == null) {
return null;
}
if (!response.Success) {
Bot.ArchiLogger.LogGenericWarning(!string.IsNullOrEmpty(response.Error) ? string.Format(Strings.WarningFailedWithError, response.Error) : Strings.WarningFailed);
return null;
}
if (response.TotalInventoryCount == 0) {
// Empty inventory
return result;
}
if ((response.Assets == null) || (response.Assets.Count == 0) || (response.Descriptions == null) || (response.Descriptions.Count == 0)) {
Bot.ArchiLogger.LogNullError(nameof(response.Assets) + " || " + nameof(response.Descriptions));
return null;
}
Dictionary<ulong, (uint AppID, Steam.Asset.EType Type, bool Tradable)> descriptionMap = new Dictionary<ulong, (uint AppID, Steam.Asset.EType Type, bool Tradable)>();
foreach (Steam.InventoryResponse.Description description in response.Descriptions.Where(description => description != null)) {
if (description.ClassID == 0) {
Bot.ArchiLogger.LogNullError(nameof(description.ClassID));
return null;
}
if (descriptionMap.ContainsKey(description.ClassID)) {
continue;
}
uint appID = 0;
if (!string.IsNullOrEmpty(description.MarketHashName)) {
appID = GetAppIDFromMarketHashName(description.MarketHashName);
}
if (appID == 0) {
appID = description.AppID;
}
Steam.Asset.EType type = Steam.Asset.EType.Unknown;
if (!string.IsNullOrEmpty(description.Type)) {
type = GetItemType(description.Type);
}
descriptionMap[description.ClassID] = (appID, type, description.Tradable);
}
foreach (Steam.Asset asset in response.Assets.Where(asset => asset != null)) {
if (descriptionMap.TryGetValue(asset.ClassID, out (uint AppID, Steam.Asset.EType Type, bool Tradable) description)) {
if (tradableOnly && !description.Tradable) {
continue;
}
asset.RealAppID = description.AppID;
asset.Type = description.Type;
}
if (wantedRealAppIDs?.Contains(asset.RealAppID) == false) {
continue;
}
result.Add(asset);
}
if (!response.MoreItems) {
return result;
}
if (response.LastAssetID == 0) {
Bot.ArchiLogger.LogNullError(nameof(response.LastAssetID));
return null;
}
startAssetID = response.LastAssetID;
}
} finally {
if (Program.GlobalConfig.InventoryLimiterDelay == 0) {
InventorySemaphore.Release();
} else {
Task.Run(async () => {
await Task.Delay(Program.GlobalConfig.InventoryLimiterDelay * 1000).ConfigureAwait(false);
InventorySemaphore.Release();
}).Forget();
}
}
}
internal async Task<Dictionary<uint, string>> GetOwnedGames(ulong steamID) {
if (steamID == 0) {
Bot.ArchiLogger.LogNullError(nameof(steamID));

View File

@@ -1026,6 +1026,22 @@ namespace ArchiSteamFarm {
return await ResponseAdvancedRedeem(steamID, args[1], args[2]).ConfigureAwait(false);
}
goto default;
case "!TAKE":
if (args.Length > 2) {
return await ResponseTake(steamID, Utilities.GetArgsString(args, 1, ","), args[2]).ConfigureAwait(false);
}
return await ResponseTake(steamID, args[1]).ConfigureAwait(false);
case "!TAKE^":
if (args.Length > 3) {
return await ResponseAdvancedTake(steamID, Utilities.GetArgsString(args, 1, ","), args[2], args[3]).ConfigureAwait(false);
}
if (args.Length > 2) {
return await ResponseAdvancedTake(steamID, args[1], args[2]).ConfigureAwait(false);
}
goto default;
case "!REJOINCHAT":
return await ResponseRejoinChat(steamID, Utilities.GetArgsString(args, 1, ",")).ConfigureAwait(false);
@@ -3150,6 +3166,212 @@ namespace ArchiSteamFarm {
return responses.Count > 0 ? string.Join("", responses) : null;
}
private async Task<string> ResponseAdvancedTake(ulong steamID, string appId, string contextId) {
if (steamID == 0 || string.IsNullOrEmpty(appId) || string.IsNullOrEmpty(contextId)) {
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(appId) + " || " + nameof(contextId));
return null;
}
if (!IsMaster(steamID)) {
return null;
}
if (!IsConnectedAndLoggedOn) {
return FormatBotResponse(Strings.BotNotConnected);
}
if (!LootingAllowed) {
return FormatBotResponse(Strings.BotLootingTemporarilyDisabled);
}
if (BotConfig.LootableTypes.Count == 0) {
return FormatBotResponse(Strings.BotLootingNoLootableTypes);
}
ulong targetSteamMasterID = GetFirstSteamMasterID();
if (targetSteamMasterID == 0) {
return FormatBotResponse(Strings.BotLootingMasterNotDefined);
}
if (targetSteamMasterID == CachedSteamID) {
return FormatBotResponse(Strings.BotSendingTradeToYourself);
}
lock (LootingSemaphore) {
if (LootingScheduled) {
return FormatBotResponse(Strings.Done);
}
LootingScheduled = true;
}
await LootingSemaphore.WaitAsync().ConfigureAwait(false);
try {
lock (LootingSemaphore) {
LootingScheduled = false;
}
HashSet<Steam.Asset> inventory = await ArchiWebHandler.GetMyCommunityInventory(true, appId, contextId).ConfigureAwait(false);
if ((inventory == null) || (inventory.Count == 0)) {
return FormatBotResponse(string.Format(Strings.ErrorIsEmpty, nameof(inventory)));
}
if (!await ArchiWebHandler.MarkSentTrades().ConfigureAwait(false)) {
return FormatBotResponse(Strings.BotLootingFailed);
}
if (!await ArchiWebHandler.SendTradeOffer(inventory, targetSteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) {
return FormatBotResponse(Strings.BotLootingFailed);
}
if (HasMobileAuthenticator) {
// Give Steam network some time to generate confirmations
await Task.Delay(3000).ConfigureAwait(false);
if (!await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, targetSteamMasterID).ConfigureAwait(false)) {
return FormatBotResponse(Strings.BotLootingFailed);
}
}
} finally {
LootingSemaphore.Release();
}
return FormatBotResponse(Strings.BotLootingSuccess);
}
private static async Task<string> ResponseAdvancedTake(ulong steamID, string botNames, string appId, string contextId) {
if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(appId) || string.IsNullOrEmpty(contextId)) {
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(appId) + " || " + nameof(contextId));
return null;
}
HashSet<Bot> bots = GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return IsOwner(steamID) ? FormatStaticResponse(string.Format(Strings.BotNotFound, botNames)) : null;
}
IEnumerable<Task<string>> tasks = bots.Select(bot => bot.ResponseAdvancedTake(steamID, appId, contextId));
ICollection<string> results;
switch (Program.GlobalConfig.OptimizationMode) {
case GlobalConfig.EOptimizationMode.MinMemoryUsage:
results = new List<string>(bots.Count);
foreach (Task<string> task in tasks) {
results.Add(await task.ConfigureAwait(false));
}
break;
default:
results = await Task.WhenAll(tasks).ConfigureAwait(false);
break;
}
List<string> responses = new List<string>(results.Where(result => !string.IsNullOrEmpty(result)));
return responses.Count > 0 ? string.Join("", responses) : null;
}
private async Task<string> ResponseTake(ulong steamID, string appId) {
if (steamID == 0 || string.IsNullOrEmpty(appId)) {
ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(appId));
return null;
}
if (!IsMaster(steamID)) {
return null;
}
if (!IsConnectedAndLoggedOn) {
return FormatBotResponse(Strings.BotNotConnected);
}
if (!LootingAllowed) {
return FormatBotResponse(Strings.BotLootingTemporarilyDisabled);
}
if (BotConfig.LootableTypes.Count == 0) {
return FormatBotResponse(Strings.BotLootingNoLootableTypes);
}
ulong targetSteamMasterID = GetFirstSteamMasterID();
if (targetSteamMasterID == 0) {
return FormatBotResponse(Strings.BotLootingMasterNotDefined);
}
if (targetSteamMasterID == CachedSteamID) {
return FormatBotResponse(Strings.BotSendingTradeToYourself);
}
lock (LootingSemaphore) {
if (LootingScheduled) {
return FormatBotResponse(Strings.Done);
}
LootingScheduled = true;
}
await LootingSemaphore.WaitAsync().ConfigureAwait(false);
try {
lock (LootingSemaphore) {
LootingScheduled = false;
}
HashSet<Steam.Asset> inventory = await ArchiWebHandler.GetMyCommunityInventory(true, appId, "2").ConfigureAwait(false);
if ((inventory == null) || (inventory.Count == 0)) {
return FormatBotResponse(string.Format(Strings.ErrorIsEmpty, nameof(inventory)));
}
if (!await ArchiWebHandler.MarkSentTrades().ConfigureAwait(false)) {
return FormatBotResponse(Strings.BotLootingFailed);
}
if (!await ArchiWebHandler.SendTradeOffer(inventory, targetSteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) {
return FormatBotResponse(Strings.BotLootingFailed);
}
if (HasMobileAuthenticator) {
// Give Steam network some time to generate confirmations
await Task.Delay(3000).ConfigureAwait(false);
if (!await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, targetSteamMasterID).ConfigureAwait(false)) {
return FormatBotResponse(Strings.BotLootingFailed);
}
}
} finally {
LootingSemaphore.Release();
}
return FormatBotResponse(Strings.BotLootingSuccess);
}
private static async Task<string> ResponseTake(ulong steamID, string botNames, string appId) {
if ((steamID == 0) || string.IsNullOrEmpty(botNames) || string.IsNullOrEmpty(appId)) {
ASF.ArchiLogger.LogNullError(nameof(steamID) + " || " + nameof(botNames) + " || " + nameof(appId));
return null;
}
HashSet<Bot> bots = GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return IsOwner(steamID) ? FormatStaticResponse(string.Format(Strings.BotNotFound, botNames)) : null;
}
IEnumerable<Task<string>> tasks = bots.Select(bot => bot.ResponseTake(steamID, appId));
ICollection<string> results;
switch (Program.GlobalConfig.OptimizationMode) {
case GlobalConfig.EOptimizationMode.MinMemoryUsage:
results = new List<string>(bots.Count);
foreach (Task<string> task in tasks) {
results.Add(await task.ConfigureAwait(false));
}
break;
default:
results = await Task.WhenAll(tasks).ConfigureAwait(false);
break;
}
List<string> responses = new List<string>(results.Where(result => !string.IsNullOrEmpty(result)));
return responses.Count > 0 ? string.Join("", responses) : null;
}
private async Task<string> ResponseLoot(ulong steamID) {
if (steamID == 0) {
ArchiLogger.LogNullError(nameof(steamID));