mirror of
https://github.com/JustArchiNET/ArchiSteamFarm.git
synced 2026-01-01 14:10:53 +00:00
Take command
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user