Add loot& and transfer& commands (#3287)

* Add `loot&` and `transfer&` commands

* Remove trailing comment
This commit is contained in:
dm1tz 2024-09-13 10:20:35 +03:00 committed by GitHub
parent 4d0f5a56ed
commit 8e85b87764
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 215 additions and 3 deletions

View file

@ -23,9 +23,21 @@
namespace ArchiSteamFarm.Steam.Data;
#pragma warning disable CA1027 // Aliases are intentional, we don't plan to combine fields
public enum EAssetRarity : byte {
Unknown,
Common,
Uncommon,
Rare
Rare,
Mythical,
Epic = Mythical,
Legendary,
Exotic = Legendary,
Ancient,
Extraordinary = Ancient,
Immortal,
Contraband = Immortal,
Arcana,
Unusual
}
#pragma warning restore CA1027 // Aliases are intentional, we don't plan to combine fields

View file

@ -191,8 +191,8 @@ public sealed class InventoryDescription {
}
foreach (CEconItem_Tag? tag in Body.tags) {
switch (tag.category) {
case "droprate":
switch (tag.category.ToUpperInvariant()) {
case "DROPRATE":
switch (tag.internal_name) {
case "droprate_0":
CachedRarity = EAssetRarity.Common;
@ -213,6 +213,20 @@ public sealed class InventoryDescription {
return CachedRarity.Value;
}
case "RARITY":
string internalName = tag.internal_name.Split('_', StringSplitOptions.RemoveEmptyEntries).Skip(1).FirstOrDefault() ?? tag.internal_name;
if (Enum.TryParse<EAssetRarity>(internalName, true, out EAssetRarity assetRarity)) {
CachedRarity = assetRarity;
return CachedRarity.Value;
}
ASF.ArchiLogger.LogGenericError(Strings.FormatWarningUnknownValuePleaseReport(nameof(tag.internal_name), tag.internal_name));
CachedRarity = EAssetRarity.Unknown;
return CachedRarity.Value;
}
}

View file

@ -236,6 +236,10 @@ public sealed class Commands {
return await ResponseAdvancedLoot(access, args[1], args[2], Utilities.GetArgsAsText(message, 3), steamID).ConfigureAwait(false);
case "LOOT^" when args.Length > 2:
return await ResponseAdvancedLoot(access, args[1], args[2]).ConfigureAwait(false);
case "LOOT&" when args.Length > 4:
return await ResponseAdvancedLootByAssetRarity(access, args[1], args[2], args[3], Utilities.GetArgsAsText(args, 4, ",")).ConfigureAwait(false);
case "LOOT&" when args.Length > 3:
return await ResponseAdvancedLootByAssetRarity(access, args[1], args[2], args[3]).ConfigureAwait(false);
case "LOOT@" when args.Length > 2:
return await ResponseLootByRealAppIDs(access, args[1], Utilities.GetArgsAsText(args, 2, ","), false, steamID).ConfigureAwait(false);
case "LOOT@":
@ -318,6 +322,10 @@ public sealed class Commands {
return await ResponseAdvancedTransfer(access, args[1], args[2], args[3], Utilities.GetArgsAsText(message, 4), steamID).ConfigureAwait(false);
case "TRANSFER^" when args.Length > 3:
return await ResponseAdvancedTransfer(access, args[1], args[2], args[3]).ConfigureAwait(false);
case "TRANSFER&" when args.Length > 5:
return await ResponseAdvancedTransferByAssetRarity(access, args[1], args[2], args[3], args[4], Utilities.GetArgsAsText(args, 5, ","), steamID).ConfigureAwait(false);
case "TRANSFER&" when args.Length > 4:
return await ResponseAdvancedTransferByAssetRarity(access, args[1], args[2], args[3], args[4]).ConfigureAwait(false);
case "TRANSFER@" when args.Length > 3:
return await ResponseTransferByRealAppIDs(access, args[1], args[2], Utilities.GetArgsAsText(message, 3), false, steamID).ConfigureAwait(false);
case "TRANSFER@" when args.Length > 2:
@ -745,6 +753,65 @@ public sealed class Commands {
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
private async Task<string?> ResponseAdvancedLootByAssetRarity(EAccess access, string targetAppID, string targetContextID, string assetRaritiesText) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
ArgumentException.ThrowIfNullOrEmpty(targetAppID);
ArgumentException.ThrowIfNullOrEmpty(targetContextID);
ArgumentException.ThrowIfNullOrEmpty(assetRaritiesText);
if (access < EAccess.Master) {
return null;
}
if (!Bot.IsConnectedAndLoggedOn) {
return FormatBotResponse(Strings.BotNotConnected);
}
if (!uint.TryParse(targetAppID, out uint appID) || (appID == 0)) {
return FormatBotResponse(Strings.FormatErrorIsInvalid(nameof(appID)));
}
if (!ulong.TryParse(targetContextID, out ulong contextID) || (contextID == 0)) {
return FormatBotResponse(Strings.FormatErrorIsInvalid(nameof(contextID)));
}
HashSet<EAssetRarity>? assetRarities = ParseAssetRarities(assetRaritiesText);
if (assetRarities == null) {
return FormatBotResponse(Strings.FormatErrorIsInvalid(nameof(assetRarities)));
}
(bool success, string message) = await Bot.Actions.SendInventory(appID, contextID, filterFunction: item => assetRarities.Contains(item.Rarity)).ConfigureAwait(false);
return FormatBotResponse(success ? message : Strings.FormatWarningFailedWithError(message));
}
private static async Task<string?> ResponseAdvancedLootByAssetRarity(EAccess access, string botNames, string appID, string contextID, string assetRaritiesText, ulong steamID = 0) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
ArgumentException.ThrowIfNullOrEmpty(botNames);
ArgumentException.ThrowIfNullOrEmpty(appID);
ArgumentException.ThrowIfNullOrEmpty(contextID);
ArgumentException.ThrowIfNullOrEmpty(assetRaritiesText);
HashSet<Bot>? bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return access >= EAccess.Owner ? FormatStaticResponse(Strings.FormatBotNotFound(botNames)) : null;
}
IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAdvancedLootByAssetRarity(GetProxyAccess(bot, access, steamID), appID, contextID, assetRaritiesText))).ConfigureAwait(false);
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
private async Task<string?> ResponseAdvancedRedeem(EAccess access, string options, string keys, ulong steamID = 0) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
@ -926,6 +993,109 @@ public sealed class Commands {
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
private async Task<string?> ResponseAdvancedTransferByAssetRarity(EAccess access, uint appID, ulong contextID, Bot targetBot, HashSet<EAssetRarity> assetRarities) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
ArgumentOutOfRangeException.ThrowIfZero(appID);
ArgumentOutOfRangeException.ThrowIfZero(contextID);
ArgumentNullException.ThrowIfNull(targetBot);
if (access < EAccess.Master) {
return null;
}
if (!Bot.IsConnectedAndLoggedOn) {
return FormatBotResponse(Strings.BotNotConnected);
}
if (!targetBot.IsConnectedAndLoggedOn) {
return FormatBotResponse(Strings.TargetBotNotConnected);
}
(bool success, string message) = await Bot.Actions.SendInventory(appID, contextID, targetBot.SteamID, filterFunction: item => assetRarities.Contains(item.Rarity)).ConfigureAwait(false);
return FormatBotResponse(success ? message : Strings.FormatWarningFailedWithError(message));
}
private async Task<string?> ResponseAdvancedTransferByAssetRarity(EAccess access, string targetAppID, string targetContextID, string botNameTo, string assetRaritiesText) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
ArgumentException.ThrowIfNullOrEmpty(targetAppID);
ArgumentException.ThrowIfNullOrEmpty(targetContextID);
ArgumentException.ThrowIfNullOrEmpty(botNameTo);
ArgumentException.ThrowIfNullOrEmpty(assetRaritiesText);
Bot? targetBot = Bot.GetBot(botNameTo);
if (targetBot == null) {
return access >= EAccess.Owner ? FormatBotResponse(Strings.FormatBotNotFound(botNameTo)) : null;
}
if (!uint.TryParse(targetAppID, out uint appID) || (appID == 0)) {
return FormatBotResponse(Strings.FormatErrorIsInvalid(nameof(appID)));
}
if (!ulong.TryParse(targetContextID, out ulong contextID) || (contextID == 0)) {
return FormatBotResponse(Strings.FormatErrorIsInvalid(nameof(contextID)));
}
HashSet<EAssetRarity>? assetRarities = ParseAssetRarities(assetRaritiesText);
if (assetRarities == null) {
return FormatBotResponse(Strings.FormatErrorIsInvalid(nameof(assetRarities)));
}
return await ResponseAdvancedTransferByAssetRarity(access, appID, contextID, targetBot, assetRarities).ConfigureAwait(false);
}
private static async Task<string?> ResponseAdvancedTransferByAssetRarity(EAccess access, string botNames, string targetAppID, string targetContextID, string botNameTo, string assetRaritiesText, ulong steamID = 0) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
}
ArgumentException.ThrowIfNullOrEmpty(botNames);
ArgumentException.ThrowIfNullOrEmpty(targetAppID);
ArgumentException.ThrowIfNullOrEmpty(targetContextID);
ArgumentException.ThrowIfNullOrEmpty(botNameTo);
ArgumentException.ThrowIfNullOrEmpty(assetRaritiesText);
HashSet<Bot>? bots = Bot.GetBots(botNames);
if ((bots == null) || (bots.Count == 0)) {
return access >= EAccess.Owner ? FormatStaticResponse(Strings.FormatBotNotFound(botNames)) : null;
}
if (!uint.TryParse(targetAppID, out uint appID) || (appID == 0)) {
return FormatStaticResponse(Strings.FormatErrorIsInvalid(nameof(appID)));
}
if (!ulong.TryParse(targetContextID, out ulong contextID) || (contextID == 0)) {
return FormatStaticResponse(Strings.FormatErrorIsInvalid(nameof(contextID)));
}
Bot? targetBot = Bot.GetBot(botNameTo);
if (targetBot == null) {
return access >= EAccess.Owner ? FormatStaticResponse(Strings.FormatBotNotFound(botNameTo)) : null;
}
HashSet<EAssetRarity>? assetRarities = ParseAssetRarities(assetRaritiesText);
if (assetRarities == null) {
return FormatStaticResponse(Strings.FormatErrorIsInvalid(nameof(assetRarities)));
}
IList<string?> results = await Utilities.InParallel(bots.Select(bot => bot.Commands.ResponseAdvancedTransferByAssetRarity(GetProxyAccess(bot, access, steamID), appID, contextID, targetBot, assetRarities))).ConfigureAwait(false);
List<string> responses = [..results.Where(static result => !string.IsNullOrEmpty(result))!];
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
private string? ResponseBackgroundGamesRedeemer(EAccess access) {
if (!Enum.IsDefined(access)) {
throw new InvalidEnumArgumentException(nameof(access), (int) access, typeof(EAccess));
@ -3257,6 +3427,22 @@ public sealed class Commands {
return responses.Count > 0 ? string.Join(Environment.NewLine, responses) : null;
}
private static HashSet<EAssetRarity>? ParseAssetRarities(string assetRaritiesText) {
string[] assetRaritiesArgs = assetRaritiesText.Split(SharedInfo.ListElementSeparators, StringSplitOptions.RemoveEmptyEntries);
HashSet<EAssetRarity> assetRarities = [];
foreach (string assetRarityArg in assetRaritiesArgs) {
if (!Enum.TryParse(assetRarityArg, true, out EAssetRarity assetRarity) || !Enum.IsDefined(assetRarity)) {
return null;
}
assetRarities.Add(assetRarity);
}
return assetRarities;
}
[Flags]
private enum ERedeemFlags : ushort {
None = 0,