diff --git a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs index 537ed5285e3c2..aabf197f93549 100644 --- a/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs +++ b/ArchiSteamFarm.OfficialPlugins.ItemsMatcher/RemoteCommunication.cs @@ -1439,7 +1439,7 @@ private async Task MatchActively(ImmutableHashSet listedUsers, Bot.ArchiLogger.LogGenericTrace($"{Bot.SteamID} <- {string.Join(", ", itemsToReceive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} | {string.Join(", ", itemsToGive.Select(static item => $"{item.RealAppID}/{item.Type}/{item.Rarity}/{item.ClassID} #{item.Amount}"))} -> {listedUser.SteamID}"); - (bool success, HashSet? tradeOfferIDs, HashSet? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, true).ConfigureAwait(false); + (bool success, HashSet? tradeOfferIDs, HashSet? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(listedUser.SteamID, itemsToGive, itemsToReceive, listedUser.TradeToken, nameof(MatchActively), true).ConfigureAwait(false); if (tradeOfferIDs?.Count > 0) { matchActivelyTradeOfferIDs.UnionWith(tradeOfferIDs); diff --git a/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs b/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs index ec0f1de0ae1ce..c78aedbd8a2f7 100644 --- a/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs +++ b/ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs @@ -56,6 +56,7 @@ public sealed class ArchiWebHandler : IDisposable { private const string EconService = "IEconService"; private const string LoyaltyRewardsService = "ILoyaltyRewardsService"; + private const byte MaxTradeOfferMessageLength = 128; private const byte MinimumSessionValidityInSeconds = 10; private const byte SessionIDLength = 24; // For maximum compatibility, should be divisible by 2 and match the length of "sessionid" property that Steam uses across their websites private const string SteamAppsService = "ISteamApps"; @@ -576,7 +577,7 @@ public async Task JoinGroup(ulong groupID) { } [PublicAPI] - public async Task<(bool Success, HashSet? TradeOfferIDs, HashSet? MobileTradeOfferIDs)> SendTradeOffer(ulong steamID, IReadOnlyCollection? itemsToGive = null, IReadOnlyCollection? itemsToReceive = null, string? token = null, bool forcedSingleOffer = false, ushort itemsPerTrade = Trading.MaxItemsPerTrade) { + public async Task<(bool Success, HashSet? TradeOfferIDs, HashSet? MobileTradeOfferIDs)> SendTradeOffer(ulong steamID, IReadOnlyCollection? itemsToGive = null, IReadOnlyCollection? itemsToReceive = null, string? token = null, string? customMessage = null, bool forcedSingleOffer = false, ushort itemsPerTrade = Trading.MaxItemsPerTrade) { if ((steamID == 0) || !new SteamID(steamID).IsIndividualAccount) { throw new ArgumentOutOfRangeException(nameof(steamID)); } @@ -620,6 +621,14 @@ public async Task JoinGroup(ulong groupID) { } } + string tradeOfferMessage = $"Sent by {SharedInfo.PublicIdentifier}/{SharedInfo.Version}"; + + if (!string.IsNullOrEmpty(customMessage)) { + byte allowedExtraMessageLength = (byte) (MaxTradeOfferMessageLength - tradeOfferMessage.Length - 3); // We're going to add a space, opening and closing bracket + + tradeOfferMessage += $" ({(customMessage.Length <= allowedExtraMessageLength ? customMessage : $"{customMessage[..(allowedExtraMessageLength - 1)]}{SteamChatMessage.ContinuationCharacter}")})"; + } + Uri request = new(SteamCommunityURL, "/tradeoffer/new/send"); Uri referer = new(SteamCommunityURL, "/tradeoffer/new"); @@ -628,7 +637,7 @@ public async Task JoinGroup(ulong groupID) { { "partner", steamID.ToString(CultureInfo.InvariantCulture) }, { "serverid", "1" }, { "trade_offer_create_params", !string.IsNullOrEmpty(token) ? new JsonObject { { "trade_offer_access_token", token } }.ToJsonText() : "" }, - { "tradeoffermessage", $"Sent by {SharedInfo.PublicIdentifier}/{SharedInfo.Version}" } + { "tradeoffermessage", tradeOfferMessage } }; HashSet tradeOfferIDs = new(trades.Count); diff --git a/ArchiSteamFarm/Steam/Interaction/Actions.cs b/ArchiSteamFarm/Steam/Interaction/Actions.cs index b6c65a063fc0f..419e4d794bba8 100644 --- a/ArchiSteamFarm/Steam/Interaction/Actions.cs +++ b/ArchiSteamFarm/Steam/Interaction/Actions.cs @@ -342,7 +342,7 @@ static async () => { } [PublicAPI] - public async Task<(bool Success, string Message)> SendInventory(IReadOnlyCollection items, ulong targetSteamID = 0, string? tradeToken = null, ushort itemsPerTrade = Trading.MaxItemsPerTrade) { + public async Task<(bool Success, string Message)> SendInventory(IReadOnlyCollection items, ulong targetSteamID = 0, string? tradeToken = null, string? customMessage = null, ushort itemsPerTrade = Trading.MaxItemsPerTrade) { if ((items == null) || (items.Count == 0)) { throw new ArgumentNullException(nameof(items)); } @@ -386,7 +386,7 @@ static async () => { return (false, Strings.BotLootingFailed); } - (bool success, _, HashSet? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(targetSteamID, items, token: tradeToken, itemsPerTrade: itemsPerTrade).ConfigureAwait(false); + (bool success, _, HashSet? mobileTradeOfferIDs) = await Bot.ArchiWebHandler.SendTradeOffer(targetSteamID, items, token: tradeToken, customMessage: customMessage, itemsPerTrade: itemsPerTrade).ConfigureAwait(false); if ((mobileTradeOfferIDs?.Count > 0) && Bot.HasMobileAuthenticator) { (bool twoFactorSuccess, _, _) = await HandleTwoFactorAuthenticationConfirmations(true, Confirmation.EConfirmationType.Trade, mobileTradeOfferIDs, true).ConfigureAwait(false); @@ -400,7 +400,7 @@ static async () => { } [PublicAPI] - public async Task<(bool Success, string Message)> SendInventory(uint appID = Asset.SteamAppID, ulong contextID = Asset.SteamCommunityContextID, ulong targetSteamID = 0, string? tradeToken = null, Func? filterFunction = null, ushort itemsPerTrade = Trading.MaxItemsPerTrade) { + public async Task<(bool Success, string Message)> SendInventory(uint appID = Asset.SteamAppID, ulong contextID = Asset.SteamCommunityContextID, ulong targetSteamID = 0, string? tradeToken = null, string? customMessage = null, Func? filterFunction = null, ushort itemsPerTrade = Trading.MaxItemsPerTrade) { ArgumentOutOfRangeException.ThrowIfZero(appID); ArgumentOutOfRangeException.ThrowIfZero(contextID); @@ -444,7 +444,7 @@ static async () => { return (false, string.Format(CultureInfo.CurrentCulture, Strings.ErrorIsEmpty, nameof(inventory))); } - return await SendInventory(inventory, targetSteamID, tradeToken, itemsPerTrade).ConfigureAwait(false); + return await SendInventory(inventory, targetSteamID, tradeToken, customMessage, itemsPerTrade).ConfigureAwait(false); } [PublicAPI]