From 40fd35df98ab74735e9efbd44136ffc68e4b087a Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Tue, 1 Oct 2024 04:43:34 +0800 Subject: [PATCH 1/7] [Core] Correction of some field names in QFaceExtra --- .../Message/Element/Implementation/Extra/QFaceExtra.cs | 8 ++++---- Lagrange.Core/Message/Entity/FaceEntity.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs index 49c4d4a12..35566ed76 100644 --- a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs +++ b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs @@ -10,13 +10,13 @@ internal class QFaceExtra { [ProtoMember(1)] public string? Field1 { get; set; } - [ProtoMember(2)] public string? Field2 { get; set; } + [ProtoMember(2)] public string? AniStickerId { get; set; } - [ProtoMember(3)] public int? FaceId { get; set; } // 318 + [ProtoMember(3)] public int? FaceId { get; set; } - [ProtoMember(4)] public int? Field4 { get; set; } + [ProtoMember(4)] public int? AniStickerPackId { get; set; } - [ProtoMember(5)] public int? Field5 { get; set; } + [ProtoMember(5)] public int? Field5 { get; set; } // maybe AniStickerType [ProtoMember(6)] public string? Field6 { get; set; } diff --git a/Lagrange.Core/Message/Entity/FaceEntity.cs b/Lagrange.Core/Message/Entity/FaceEntity.cs index c149e3569..c05d36e63 100644 --- a/Lagrange.Core/Message/Entity/FaceEntity.cs +++ b/Lagrange.Core/Message/Entity/FaceEntity.cs @@ -27,9 +27,9 @@ IEnumerable IMessageEntity.PackElement() var qFace = new QFaceExtra { Field1 = "1", - Field2 = "8", + AniStickerId = "8", FaceId = FaceId, - Field4 = 1, + AniStickerPackId = 1, Field5 = 1, Field6 = "", Preview = "", From 3043fd02ac3c4d3d063c0ae6247bc56ed240c486 Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Tue, 1 Oct 2024 05:47:07 +0800 Subject: [PATCH 2/7] [Core] Correction of some field names in QFaceExtra x2 --- .../Message/Element/Implementation/Extra/QFaceExtra.cs | 8 ++++---- Lagrange.Core/Message/Entity/FaceEntity.cs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs index 35566ed76..48bee67de 100644 --- a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs +++ b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs @@ -8,15 +8,15 @@ namespace Lagrange.Core.Internal.Packets.Message.Element.Implementation.Extra; [ProtoContract] internal class QFaceExtra { - [ProtoMember(1)] public string? Field1 { get; set; } + [ProtoMember(1)] public string? AniStickerPackId { get; set; } [ProtoMember(2)] public string? AniStickerId { get; set; } - [ProtoMember(3)] public int? FaceId { get; set; } + [ProtoMember(3)] public int? FaceId { get; set; } // 318 - [ProtoMember(4)] public int? AniStickerPackId { get; set; } + [ProtoMember(4)] public int? Field4 { get; set; } - [ProtoMember(5)] public int? Field5 { get; set; } // maybe AniStickerType + [ProtoMember(5)] public int? AniStickerType { get; set; } [ProtoMember(6)] public string? Field6 { get; set; } diff --git a/Lagrange.Core/Message/Entity/FaceEntity.cs b/Lagrange.Core/Message/Entity/FaceEntity.cs index c05d36e63..2449b57fe 100644 --- a/Lagrange.Core/Message/Entity/FaceEntity.cs +++ b/Lagrange.Core/Message/Entity/FaceEntity.cs @@ -26,11 +26,11 @@ IEnumerable IMessageEntity.PackElement() { var qFace = new QFaceExtra { - Field1 = "1", + AniStickerPackId = "1", AniStickerId = "8", FaceId = FaceId, - AniStickerPackId = 1, - Field5 = 1, + Field4 = 1, + AniStickerType = 1, Field6 = "", Preview = "", Field9 = 1 From 7a3da5b7fd03437d9ec9923885a5fad586603260 Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Mon, 14 Oct 2024 13:09:16 +0800 Subject: [PATCH 3/7] [Core] Introduce `0x9154_1` & spilt `QFaceExtra` --- .../Extra/{QFaceExtra.cs => QBigFaceExtra.cs} | 2 +- .../Implementation/Extra/QSmallFaceExtra.cs | 13 ++-- .../Oidb/Request/OidbSvcTrpcTcp0x9154_1.cs | 17 +++++ .../OidbSvcTrpcTcp0x9154_1Response.cs | 70 +++++++++++++++++++ Lagrange.Core/Message/Entity/FaceEntity.cs | 9 ++- 5 files changed, 102 insertions(+), 9 deletions(-) rename Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/{QFaceExtra.cs => QBigFaceExtra.cs} (96%) create mode 100644 Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x9154_1.cs create mode 100644 Lagrange.Core/Internal/Packets/Service/Oidb/Response/OidbSvcTrpcTcp0x9154_1Response.cs diff --git a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QBigFaceExtra.cs similarity index 96% rename from Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs rename to Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QBigFaceExtra.cs index 48bee67de..db7a9defa 100644 --- a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QFaceExtra.cs +++ b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QBigFaceExtra.cs @@ -6,7 +6,7 @@ namespace Lagrange.Core.Internal.Packets.Message.Element.Implementation.Extra; /// Constructed at , Service Type 33, Big face /// [ProtoContract] -internal class QFaceExtra +internal class QBigFaceExtra { [ProtoMember(1)] public string? AniStickerPackId { get; set; } diff --git a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QSmallFaceExtra.cs b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QSmallFaceExtra.cs index 4c53d714a..749dcd9c1 100644 --- a/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QSmallFaceExtra.cs +++ b/Lagrange.Core/Internal/Packets/Message/Element/Implementation/Extra/QSmallFaceExtra.cs @@ -1,15 +1,16 @@ using ProtoBuf; - -#pragma warning disable CS8618 namespace Lagrange.Core.Internal.Packets.Message.Element.Implementation.Extra; +/// +/// Constructed at , Service Type 33, Small face (FaceId >= 260) +/// [ProtoContract] internal class QSmallFaceExtra { [ProtoMember(1)] public uint FaceId { get; set; } - - [ProtoMember(2)] public string Preview { get; set; } - - [ProtoMember(3)] public string Preview2 { get; set; } + + [ProtoMember(2)] public string? Text { get; set; } + + [ProtoMember(3)] public string? CompatText { get; set; } } \ No newline at end of file diff --git a/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x9154_1.cs b/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x9154_1.cs new file mode 100644 index 000000000..09c246d12 --- /dev/null +++ b/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x9154_1.cs @@ -0,0 +1,17 @@ +using ProtoBuf; + +#pragma warning disable CS8618 +// ReSharper disable InconsistentNaming + +namespace Lagrange.Core.Internal.Packets.Service.Oidb.Request; + +[ProtoContract] +[OidbSvcTrpcTcp(0x9154, 1)] +internal class OidbSvcTrpcTcp0x9154_1 +{ + [ProtoMember(1)] public int Field1 { get; set; } // 0 + + [ProtoMember(2)] public int Field2 { get; set; } // 7 + + [ProtoMember(3)] public string Field3 { get; set; } // 0 +} \ No newline at end of file diff --git a/Lagrange.Core/Internal/Packets/Service/Oidb/Response/OidbSvcTrpcTcp0x9154_1Response.cs b/Lagrange.Core/Internal/Packets/Service/Oidb/Response/OidbSvcTrpcTcp0x9154_1Response.cs new file mode 100644 index 000000000..8572e5746 --- /dev/null +++ b/Lagrange.Core/Internal/Packets/Service/Oidb/Response/OidbSvcTrpcTcp0x9154_1Response.cs @@ -0,0 +1,70 @@ +using ProtoBuf; + +#pragma warning disable CS8618 +// Resharper disable InconsistentNaming + +namespace Lagrange.Core.Internal.Packets.Service.Oidb.Response; + +[ProtoContract] +internal class OidbSvcTrpcTcp0x9154_1Response +{ + [ProtoMember(1)] public int Field1 { get; set; } + + [ProtoMember(2)] public OidbSvcTrpcTcp0x9154_1ResponseContent CommonFace { get; set; } + + [ProtoMember(3)] public OidbSvcTrpcTcp0x9154_1ResponseContent SpecialBigFace { get; set; } + + [ProtoMember(4)] public OidbSvcTrpcTcp0x9154_1ResponseContent SpecialMagicFace { get; set; } +} + +[ProtoContract] +internal class OidbSvcTrpcTcp0x9154_1ResponseContent +{ + [ProtoMember(1)] public OidbSvcTrpcTcp0x9154_1ResponseContentEmojiList[] EmojiList { get; set; } + + [ProtoMember(2)] public OidbSvcTrpcTcp0x9154_1ResponseContentResourceUrl? ResourceUrl { get; set; } +} + +[ProtoContract] +internal class OidbSvcTrpcTcp0x9154_1ResponseContentEmojiList +{ + [ProtoMember(1)] public string EmojiPackName { get; set; } + + [ProtoMember(2)] public OidbSvcTrpcTcp0x9154_1ResponseContentEmoji[] EmojiDetail { get; set; } +} + +[ProtoContract] +internal class OidbSvcTrpcTcp0x9154_1ResponseContentEmoji +{ + [ProtoMember(1)] public string? QSid { get; set; } + + [ProtoMember(2)] public string? QDes { get; set; } + + [ProtoMember(3)] public string? EMCode { get; set; } + + [ProtoMember(4)] public string? QCid { get; set; } + + [ProtoMember(5)] public string? AniStickerType { get; set; } + + [ProtoMember(6)] public string? AniStickerPackId { get; set; } + + [ProtoMember(7)] public string? AniStickerId { get; set; } + + [ProtoMember(8)] public OidbSvcTrpcTcp0x9154_1ResponseContentResourceUrl? Url { get; set; } + + [ProtoMember(9)] public string[]? EmojiNameAilas { get; set; } + + [ProtoMember(10)] public string? Unknown10 { get; set; } + + [ProtoMember(13)] public string? AniStickerWidth { get; set; } + + [ProtoMember(14)] public string? AniStickerHeight { get; set; } +} + +[ProtoContract] +internal class OidbSvcTrpcTcp0x9154_1ResponseContentResourceUrl +{ + [ProtoMember(1)] public string? BaseUrl { get; set; } + + [ProtoMember(2)] public string? AdvUrl { get; set; } +} \ No newline at end of file diff --git a/Lagrange.Core/Message/Entity/FaceEntity.cs b/Lagrange.Core/Message/Entity/FaceEntity.cs index 2449b57fe..da6058551 100644 --- a/Lagrange.Core/Message/Entity/FaceEntity.cs +++ b/Lagrange.Core/Message/Entity/FaceEntity.cs @@ -24,7 +24,7 @@ IEnumerable IMessageEntity.PackElement() { if (IsLargeFace) { - var qFace = new QFaceExtra + var qFace = new QBigFaceExtra { AniStickerPackId = "1", AniStickerId = "8", @@ -51,6 +51,11 @@ IEnumerable IMessageEntity.PackElement() } }; } + // TODO: + // else if (FaceId >= 260) + // { + // + // } return new Elem[] { new() { Face = new Face { Index = FaceId } } }; } @@ -65,7 +70,7 @@ IEnumerable IMessageEntity.PackElement() if (elems.CommonElem is { ServiceType:37, PbElem: not null } common) { - var qFace = Serializer.Deserialize(common.PbElem.AsSpan()); + var qFace = Serializer.Deserialize(common.PbElem.AsSpan()); ushort? faceId = (ushort?)qFace.FaceId; if (faceId != null) return new FaceEntity((ushort)faceId, true); From d7a2af7c8abe976700431daafb7f2088be9b4d72 Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Mon, 21 Oct 2024 16:18:56 +0800 Subject: [PATCH 4/7] [Core] faceId >= 260 --- Lagrange.Core/Message/Entity/FaceEntity.cs | 34 +++++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/Lagrange.Core/Message/Entity/FaceEntity.cs b/Lagrange.Core/Message/Entity/FaceEntity.cs index 5294b83dc..03ddbd311 100644 --- a/Lagrange.Core/Message/Entity/FaceEntity.cs +++ b/Lagrange.Core/Message/Entity/FaceEntity.cs @@ -24,7 +24,7 @@ IEnumerable IMessageEntity.PackElement() { if (IsLargeFace) { - var qFace = new QBigFaceExtra + var qBigFace = new QBigFaceExtra { AniStickerPackId = "1", AniStickerId = "8", @@ -36,8 +36,7 @@ IEnumerable IMessageEntity.PackElement() Field9 = 1 }; using var stream = new MemoryStream(); - Serializer.Serialize(stream, qFace); - + Serializer.Serialize(stream, qBigFace); return new Elem[] { new() @@ -51,11 +50,30 @@ IEnumerable IMessageEntity.PackElement() } }; } - // TODO: - // else if (FaceId >= 260) - // { - // - // } + + if (FaceId >= 260) + { + var qSmallFace = new QSmallFaceExtra + { + FaceId = FaceId, + Text = "", + CompatText = "" + }; + using var stream = new MemoryStream(); + Serializer.Serialize(stream, qSmallFace); + return new Elem[] + { + new() + { + CommonElem = new CommonElem + { + ServiceType = 33, + PbElem = stream.ToArray(), + BusinessType = 1 + } + } + }; + } return new Elem[] { new() { Face = new Face { Index = FaceId } } }; } From e186705df8cca394b7d55a3aae88d41264831c68 Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Tue, 22 Oct 2024 04:54:36 +0800 Subject: [PATCH 5/7] [All] Fix the issue of sending super emoticons & add JoinEmojiChan --- Lagrange.Core/Common/Entity/SysFaceEntry.cs | 67 ++++++++++++++++++ .../Common/Interface/Api/OperationExt.cs | 12 ++++ .../Logic/Implementation/CachingLogic.cs | 39 ++++++++++- .../Logic/Implementation/MessagingLogic.cs | 9 +++ .../Logic/Implementation/OperationLogic.cs | 42 ++++++++++-- .../Event/Action/FriendJoinEmojiChainEvent.cs | 14 ++++ .../Event/Action/GroupJoinEmojiChainEvent.cs | 14 ++++ .../Event/Action/JoinEmojiChainEvent.cs | 22 ++++++ .../Event/System/FetchFullSysFacesEvent.cs | 22 ++++++ .../Oidb/Request/OidbSvcTrpcTcp.0x90EE_1.cs | 24 +++++++ .../OidbSvcTrpcTcp0x9154_1Response.cs | 34 +++++++--- .../Service/Action/JoinEmojiChainService.cs | 41 +++++++++++ .../System/FetchFullSysFacesService.cs | 68 +++++++++++++++++++ Lagrange.Core/Message/Entity/FaceEntity.cs | 27 ++++---- Lagrange.Core/Message/MessageBuilder.cs | 2 +- .../Action/OneBotGroupJoinEmojiChain.cs | 11 +++ .../Action/OneBotPrivateJoinEmojiChain.cs | 11 +++ .../Generic/FriendJoinEmojiChainOperation.cs | 27 ++++++++ .../Generic/GroupJoinEmojiChainOperation.cs | 27 ++++++++ Lagrange.OneBot/Message/Entity/FaceSegment.cs | 5 +- 20 files changed, 486 insertions(+), 32 deletions(-) create mode 100644 Lagrange.Core/Common/Entity/SysFaceEntry.cs create mode 100644 Lagrange.Core/Internal/Event/Action/FriendJoinEmojiChainEvent.cs create mode 100644 Lagrange.Core/Internal/Event/Action/GroupJoinEmojiChainEvent.cs create mode 100644 Lagrange.Core/Internal/Event/Action/JoinEmojiChainEvent.cs create mode 100644 Lagrange.Core/Internal/Event/System/FetchFullSysFacesEvent.cs create mode 100644 Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp.0x90EE_1.cs create mode 100644 Lagrange.Core/Internal/Service/Action/JoinEmojiChainService.cs create mode 100644 Lagrange.Core/Internal/Service/System/FetchFullSysFacesService.cs create mode 100644 Lagrange.OneBot/Core/Entity/Action/OneBotGroupJoinEmojiChain.cs create mode 100644 Lagrange.OneBot/Core/Entity/Action/OneBotPrivateJoinEmojiChain.cs create mode 100644 Lagrange.OneBot/Core/Operation/Generic/FriendJoinEmojiChainOperation.cs create mode 100644 Lagrange.OneBot/Core/Operation/Generic/GroupJoinEmojiChainOperation.cs diff --git a/Lagrange.Core/Common/Entity/SysFaceEntry.cs b/Lagrange.Core/Common/Entity/SysFaceEntry.cs new file mode 100644 index 000000000..7bbf0468e --- /dev/null +++ b/Lagrange.Core/Common/Entity/SysFaceEntry.cs @@ -0,0 +1,67 @@ +namespace Lagrange.Core.Common.Entity; + +[Serializable] +public class SysFaceEntry +{ + public string QSid { get; set; } + + public string? QDes { get; set; } + + public string? EMCode { get; set; } + + public int? QCid { get; set; } + + public int? AniStickerType { get; set; } + + public int? AniStickerPackId { get; set; } + + public int? AniStickerId { get; set; } + + public string? Url { get; set; } + + public string[]? EmojiNameAlias { get; set; } + + public int? AniStickerWidth { get; set; } + + public int? AniStickerHeight { get; set; } + + public SysFaceEntry(string qSid, string? qDes, string? emCode, int? qCid, int? aniStickerType, + int? aniStickerPackId, int? aniStickerId, string? url, string[]? emojiNameAlias, int? aniStickerWidth, + int? aniStickerHeight) + { + QSid = qSid; + QDes = qDes; + EMCode = emCode; + QCid = qCid; + AniStickerType = aniStickerType; + AniStickerPackId = aniStickerPackId; + AniStickerId = aniStickerId; + Url = url; + EmojiNameAlias = emojiNameAlias; + AniStickerWidth = aniStickerWidth; + AniStickerHeight = aniStickerHeight; + } +} + +[Serializable] +public class SysFacePackEntry +{ + public string EmojiPackName { get; set; } + + public SysFaceEntry[] Emojis { get; set; } + + public SysFacePackEntry(string emojiPackName, SysFaceEntry[] emojis) + { + EmojiPackName = emojiPackName; + Emojis = emojis; + } + + public uint[] GetUniqueSuperQSids((int AniStickerType, int AniStickerPackId)[] excludeAniStickerTypesAndPackIds) + => Emojis + .Where(e => e.AniStickerType is not null + && e.AniStickerPackId is not null + && !excludeAniStickerTypesAndPackIds.Contains((e.AniStickerType.Value, e.AniStickerPackId.Value))) + .Select(e => uint.Parse(e.QSid)) + .Distinct() + .ToArray(); +} \ No newline at end of file diff --git a/Lagrange.Core/Common/Interface/Api/OperationExt.cs b/Lagrange.Core/Common/Interface/Api/OperationExt.cs index 3900a4416..fee6b08a2 100644 --- a/Lagrange.Core/Common/Interface/Api/OperationExt.cs +++ b/Lagrange.Core/Common/Interface/Api/OperationExt.cs @@ -249,4 +249,16 @@ public static Task FriendShake(this BotContext bot, uint friendUi /// The avatar object, public static Task SetAvatar(this BotContext bot, ImageEntity avatar) => bot.ContextCollection.Business.OperationLogic.SetAvatar(avatar); + + public static Task FetchSuperFaceId(this BotContext bot, uint id) + => bot.ContextCollection.Business.OperationLogic.FetchSuperFaceId(id); + + public static Task FetchFaceEntity(this BotContext bot, uint id) + => bot.ContextCollection.Business.OperationLogic.FetchFaceEntity(id); + + public static Task GroupJoinEmojiChain(this BotContext bot, uint groupUin, uint emojiId, uint targetMessageSeq) + => bot.ContextCollection.Business.OperationLogic.GroupJoinEmojiChain(groupUin, emojiId, targetMessageSeq); + + public static Task FriendJoinEmojiChain(this BotContext bot, uint friendUin, uint emojiId, uint targetMessageSeq) + => bot.ContextCollection.Business.OperationLogic.FriendJoinEmojiChain(friendUin, emojiId, targetMessageSeq); } diff --git a/Lagrange.Core/Internal/Context/Logic/Implementation/CachingLogic.cs b/Lagrange.Core/Internal/Context/Logic/Implementation/CachingLogic.cs index 645946768..cedf4bdfd 100644 --- a/Lagrange.Core/Internal/Context/Logic/Implementation/CachingLogic.cs +++ b/Lagrange.Core/Internal/Context/Logic/Implementation/CachingLogic.cs @@ -25,6 +25,9 @@ internal class CachingLogic : LogicBase private readonly ConcurrentDictionary _cacheUsers; + private readonly Dictionary _cacheFaceEntities; + private readonly List _cacheSuperFaceId; + internal CachingLogic(ContextCollection collection) : base(collection) { _uinToUid = new Dictionary(); @@ -35,13 +38,17 @@ internal CachingLogic(ContextCollection collection) : base(collection) _cachedGroupMembers = new Dictionary>(); _cacheUsers = new ConcurrentDictionary(); + + _cacheFaceEntities = new Dictionary(); + _cacheSuperFaceId = new List(); } public override Task Incoming(ProtocolEvent e) { return e switch { - GroupSysDecreaseEvent groupSysDecreaseEvent when groupSysDecreaseEvent.MemberUid != Collection.Keystore.Uid => CacheUid(groupSysDecreaseEvent.GroupUin, true), + GroupSysDecreaseEvent groupSysDecreaseEvent when groupSysDecreaseEvent.MemberUid != Collection.Keystore.Uid + => CacheUid(groupSysDecreaseEvent.GroupUin, true), GroupSysIncreaseEvent groupSysIncreaseEvent => CacheUid(groupSysIncreaseEvent.GroupUin, true), GroupSysAdminEvent groupSysAdminEvent => CacheUid(groupSysAdminEvent.GroupUin, true), _ => Task.CompletedTask, @@ -92,6 +99,7 @@ public async Task> GetCachedMembers(uint groupUin, bool ref await ResolveMembersUid(groupUin); return _cachedGroupMembers.TryGetValue(groupUin, out members) ? members : new List(); } + return members; } @@ -142,6 +150,7 @@ private async Task ResolveFriendsUidAndFriendGroups() { friend.Group = new(friend.Group.GroupId, friendGroups[friend.Group.GroupId]); } + friends.AddRange(result.Friends); next = result.NextUin; @@ -190,4 +199,32 @@ private async Task ResolveUser(uint uin) _cacheUsers.AddOrUpdate(uin, @event.UserInfo, (_key, _value) => @event.UserInfo); } } + + private async Task ResolveEmojiCache() + { + var fetchSysEmojisEvent = FetchFullSysFacesEvent.Create(); + var events = await Collection.Business.SendEvent(fetchSysEmojisEvent); + var emojiPacks = ((FetchFullSysFacesEvent)events[0]).FacePacks; + + emojiPacks + .SelectMany(pack => pack.Emojis) + .Where(emoji => uint.TryParse(emoji.QSid, out _)) + .ToList() + .ForEach(emoji => _cacheFaceEntities[uint.Parse(emoji.QSid)] = emoji); + + _cacheSuperFaceId.AddRange(emojiPacks + .SelectMany(emojiPack => emojiPack.GetUniqueSuperQSids(new[] { (1, 1) }))); + } + + public async Task GetCachedIsSuperFaceId(uint id) + { + if (!_cacheSuperFaceId.Any()) await ResolveEmojiCache(); + return _cacheSuperFaceId.Contains(id); + } + + public async Task GetCachedFaceEntity(uint faceId) + { + if (!_cacheFaceEntities.ContainsKey(faceId)) await ResolveEmojiCache(); + return _cacheFaceEntities.GetValueOrDefault(faceId); + } } \ No newline at end of file diff --git a/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs b/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs index 9da1c8f2c..690d8a188 100644 --- a/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs +++ b/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs @@ -10,6 +10,7 @@ using Lagrange.Core.Message; using Lagrange.Core.Message.Entity; using Lagrange.Core.Message.Filter; +using Lagrange.Core.Utility.Extension; using FriendPokeEvent = Lagrange.Core.Event.EventArg.FriendPokeEvent; using GroupPokeEvent = Lagrange.Core.Event.EventArg.GroupPokeEvent; @@ -382,6 +383,14 @@ private async Task ResolveOutgoingChain(MessageChain chain) { switch (entity) { + case FaceEntity face: + { + var cache = Collection.Business.CachingLogic; + face.IsLargeFace ??= await cache.GetCachedIsSuperFaceId(face.FaceId); + face.SysFaceEntry ??= await cache.GetCachedFaceEntity(face.FaceId); + break; + } + case ForwardEntity forward when forward.TargetUin != 0: { var cache = Collection.Business.CachingLogic; diff --git a/Lagrange.Core/Internal/Context/Logic/Implementation/OperationLogic.cs b/Lagrange.Core/Internal/Context/Logic/Implementation/OperationLogic.cs index fdf82a6aa..a6edf5e61 100644 --- a/Lagrange.Core/Internal/Context/Logic/Implementation/OperationLogic.cs +++ b/Lagrange.Core/Internal/Context/Logic/Implementation/OperationLogic.cs @@ -212,6 +212,7 @@ public async Task> FetchGroupFSList(uint groupUin, string targ if (((GroupFSListEvent)events[0]).IsEnd) break; startIndex += 20; } + return entries; } @@ -222,7 +223,8 @@ public async Task FetchGroupFSDownload(uint groupUin, string fileId) return $"{((GroupFSDownloadEvent)events[0]).FileUrl}{fileId}"; } - public async Task<(int, string)> GroupFSMove(uint groupUin, string fileId, string parentDirectory, string targetDirectory) + public async Task<(int, string)> GroupFSMove(uint groupUin, string fileId, string parentDirectory, + string targetDirectory) { var groupFSMoveEvent = GroupFSMoveEvent.Create(groupUin, fileId, parentDirectory, targetDirectory); var events = await Collection.Business.SendEvent(groupFSMoveEvent); @@ -271,7 +273,8 @@ public Task GroupFSUpload(uint groupUin, FileEntity fileEntity, string tar { try { - return FileUploader.UploadGroup(Collection, MessageBuilder.Group(groupUin).Build(), fileEntity, targetDirectory); + return FileUploader.UploadGroup(Collection, MessageBuilder.Group(groupUin).Build(), fileEntity, + targetDirectory); } catch { @@ -324,7 +327,8 @@ public async Task RecallFriendMessage(uint friendUin, MessageResult result if (result.Sequence == null) return false; if (await Collection.Business.CachingLogic.ResolveUid(null, friendUin) is not { } uid) return false; - var recallMessageEvent = RecallFriendMessageEvent.Create(uid, result.ClientSequence, result.Sequence ?? 0, (uint)(result.MessageId & uint.MaxValue), result.Timestamp); + var recallMessageEvent = RecallFriendMessageEvent.Create(uid, result.ClientSequence, result.Sequence ?? 0, + (uint)(result.MessageId & uint.MaxValue), result.Timestamp); var events = await Collection.Business.SendEvent(recallMessageEvent); return events.Count != 0 && ((RecallFriendMessageEvent)events[0]).ResultCode == 0; } @@ -334,7 +338,8 @@ public async Task RecallFriendMessage(MessageChain chain) if (await Collection.Business.CachingLogic.ResolveUid(null, chain.TargetUin) is not { } uid) return false; uint timestamp = (uint)new DateTimeOffset(chain.Time).ToUnixTimeSeconds(); - var recallMessageEvent = RecallFriendMessageEvent.Create(uid, chain.ClientSequence, chain.Sequence, (uint)(chain.MessageId & uint.MaxValue), timestamp); + var recallMessageEvent = RecallFriendMessageEvent.Create(uid, chain.ClientSequence, chain.Sequence, + (uint)(chain.MessageId & uint.MaxValue), timestamp); var events = await Collection.Business.SendEvent(recallMessageEvent); return events.Count != 0 && ((RecallFriendMessageEvent)events[0]).ResultCode == 0; } @@ -350,7 +355,8 @@ public async Task RecallFriendMessage(MessageChain chain) foreach (var result in resolved) { - var uins = await Task.WhenAll(ResolveUid(result.InvitorMemberUid), ResolveUid(result.TargetMemberUid), ResolveUid(result.OperatorUid)); + var uins = await Task.WhenAll(ResolveUid(result.InvitorMemberUid), ResolveUid(result.TargetMemberUid), + ResolveUid(result.OperatorUid)); uint invitorUin = uins[0]; uint targetUin = uins[1]; uint operatorUin = uins[2]; @@ -487,7 +493,8 @@ public async Task SetGroupRequest(uint groupUin, ulong sequence, uint type return results.Count != 0 && results[0].ResultCode == 0; } - public async Task SetGroupFilteredRequest(uint groupUin, ulong sequence, uint type, bool accept, string reason) + public async Task SetGroupFilteredRequest(uint groupUin, ulong sequence, uint type, bool accept, + string reason) { var inviteEvent = SetGroupFilteredRequestEvent.Create(accept, groupUin, sequence, type, reason); var results = await Collection.Business.SendEvent(inviteEvent); @@ -664,7 +671,8 @@ public async Task SetAvatar(ImageEntity avatar) var ticket = ((HighwayUrlEvent)highwayUrlResults[0]).SigSession; var md5 = avatar.ImageStream.Value.Md5().UnHex(); - return await Collection.Highway.UploadSrcByStreamAsync(90, avatar.ImageStream.Value, ticket, md5, Array.Empty()); + return await Collection.Highway.UploadSrcByStreamAsync(90, avatar.ImageStream.Value, ticket, md5, + Array.Empty()); } public async Task GroupSetAvatar(uint groupUin, ImageEntity avatar) @@ -697,4 +705,24 @@ public async Task GroupSetAvatar(uint groupUin, ImageEntity avatar) var ret = (FetchGroupAtAllRemainEvent)results[0]; return (ret.RemainAtAllCountForUin, ret.RemainAtAllCountForGroup); } + + public async Task FetchSuperFaceId(uint id) => await Collection.Business.CachingLogic.GetCachedIsSuperFaceId(id); + + public async Task FetchFaceEntity(uint id) => await Collection.Business.CachingLogic.GetCachedFaceEntity(id); + + public async Task GroupJoinEmojiChain(uint groupUin, uint emojiId, uint targetMessageSeq) + { + var groupJoinEmojiChainEvent = GroupJoinEmojiChainEvent.Create(targetMessageSeq, emojiId, groupUin); + var results = await Collection.Business.SendEvent(groupJoinEmojiChainEvent); + return results.Count != 0 && results[0].ResultCode == 0; + } + + public async Task FriendJoinEmojiChain(uint friendUin, uint emojiId, uint targetMessageSeq) + { + string? friendUid = await Collection.Business.CachingLogic.ResolveUid(null, friendUin); + if (friendUid == null) return false; + var friendJoinEmojiChainEvent = FriendJoinEmojiChainEvent.Create(targetMessageSeq, emojiId, friendUid); + var results = await Collection.Business.SendEvent(friendJoinEmojiChainEvent); + return results.Count != 0 && results[0].ResultCode == 0; + } } \ No newline at end of file diff --git a/Lagrange.Core/Internal/Event/Action/FriendJoinEmojiChainEvent.cs b/Lagrange.Core/Internal/Event/Action/FriendJoinEmojiChainEvent.cs new file mode 100644 index 000000000..1846f5048 --- /dev/null +++ b/Lagrange.Core/Internal/Event/Action/FriendJoinEmojiChainEvent.cs @@ -0,0 +1,14 @@ +namespace Lagrange.Core.Internal.Event.Action; + +internal class FriendJoinEmojiChainEvent : JoinEmojiChainEvent +{ + private FriendJoinEmojiChainEvent(uint targetMessageSeq, uint targetFaceId, string friendUid) : base(targetMessageSeq, targetFaceId) + { + FriendUid = friendUid; + } + + private FriendJoinEmojiChainEvent(int resultCode) : base(resultCode) { } + + public static FriendJoinEmojiChainEvent Create(uint targetMessageSeq, uint targetFaceId, string friendUid) + => new(targetMessageSeq, targetFaceId, friendUid); +} \ No newline at end of file diff --git a/Lagrange.Core/Internal/Event/Action/GroupJoinEmojiChainEvent.cs b/Lagrange.Core/Internal/Event/Action/GroupJoinEmojiChainEvent.cs new file mode 100644 index 000000000..8f58544ec --- /dev/null +++ b/Lagrange.Core/Internal/Event/Action/GroupJoinEmojiChainEvent.cs @@ -0,0 +1,14 @@ +namespace Lagrange.Core.Internal.Event.Action; + +internal class GroupJoinEmojiChainEvent : JoinEmojiChainEvent +{ + private GroupJoinEmojiChainEvent(uint targetMessageSeq, uint targetFaceId, uint groupUin) : base(targetMessageSeq, targetFaceId) + { + GroupUin = groupUin; + } + + private GroupJoinEmojiChainEvent(int resultCode) : base(resultCode) { } + + public static GroupJoinEmojiChainEvent Create(uint targetMessageSeq, uint targetFaceId, uint groupUin) + => new(targetMessageSeq, targetFaceId, groupUin); +} diff --git a/Lagrange.Core/Internal/Event/Action/JoinEmojiChainEvent.cs b/Lagrange.Core/Internal/Event/Action/JoinEmojiChainEvent.cs new file mode 100644 index 000000000..7f0c0d74b --- /dev/null +++ b/Lagrange.Core/Internal/Event/Action/JoinEmojiChainEvent.cs @@ -0,0 +1,22 @@ +namespace Lagrange.Core.Internal.Event.Action; + +internal class JoinEmojiChainEvent : ProtocolEvent +{ + public uint TargetMessageSeq { get; set; } + + public uint TargetFaceId { get; set; } + + public uint? GroupUin { get; set; } + + public string? FriendUid { get; set; } + + protected JoinEmojiChainEvent(uint targetMessageSeq, uint targetFaceId) : base(true) + { + TargetMessageSeq = targetMessageSeq; + TargetFaceId = targetFaceId; + } + + protected JoinEmojiChainEvent(int resultCode) : base(resultCode) { } + + public static JoinEmojiChainEvent Result(int resultCode) => new(resultCode); +} diff --git a/Lagrange.Core/Internal/Event/System/FetchFullSysFacesEvent.cs b/Lagrange.Core/Internal/Event/System/FetchFullSysFacesEvent.cs new file mode 100644 index 000000000..71c64950d --- /dev/null +++ b/Lagrange.Core/Internal/Event/System/FetchFullSysFacesEvent.cs @@ -0,0 +1,22 @@ +using Lagrange.Core.Common.Entity; + +namespace Lagrange.Core.Internal.Event.System; + +internal class FetchFullSysFacesEvent : ProtocolEvent +{ + public List FacePacks { get; set; } + + private FetchFullSysFacesEvent(List facePacks) : base(true) + { + FacePacks = facePacks; + } + + private FetchFullSysFacesEvent(int resultCode, List facePacks) : base(resultCode) + { + FacePacks = facePacks; + } + + public static FetchFullSysFacesEvent Create() => new(new List()); + + public static FetchFullSysFacesEvent Result(int resultCode, List emojiPacks) => new(resultCode, emojiPacks); +} \ No newline at end of file diff --git a/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp.0x90EE_1.cs b/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp.0x90EE_1.cs new file mode 100644 index 000000000..0ca6e733d --- /dev/null +++ b/Lagrange.Core/Internal/Packets/Service/Oidb/Request/OidbSvcTrpcTcp.0x90EE_1.cs @@ -0,0 +1,24 @@ +using ProtoBuf; + +#pragma warning disable CS8618 +// ReSharper disable InconsistentNaming + +namespace Lagrange.Core.Internal.Packets.Service.Oidb.Request; + +[ProtoContract] +[OidbSvcTrpcTcp(0x90EE, 1)] +internal class OidbSvcTrpcTcp0x90EE_1 +{ + [ProtoMember(1)] public uint FaceId { get; set; } + + [ProtoMember(2)] public uint TargetMsgSeq { get; set; } + + [ProtoMember(3)] public uint TargetMsgSeq_2 { get; set; } + + [ProtoMember(4)] public int Field4 { get; set; } // group 2 friend 1 ? + + [ProtoMember(5)] public uint? TargetGroupId { get; set; } + + [ProtoMember(6)] public string? TargetUid { get; set; } + +} \ No newline at end of file diff --git a/Lagrange.Core/Internal/Packets/Service/Oidb/Response/OidbSvcTrpcTcp0x9154_1Response.cs b/Lagrange.Core/Internal/Packets/Service/Oidb/Response/OidbSvcTrpcTcp0x9154_1Response.cs index 8572e5746..a29ce92dd 100644 --- a/Lagrange.Core/Internal/Packets/Service/Oidb/Response/OidbSvcTrpcTcp0x9154_1Response.cs +++ b/Lagrange.Core/Internal/Packets/Service/Oidb/Response/OidbSvcTrpcTcp0x9154_1Response.cs @@ -14,7 +14,7 @@ internal class OidbSvcTrpcTcp0x9154_1Response [ProtoMember(3)] public OidbSvcTrpcTcp0x9154_1ResponseContent SpecialBigFace { get; set; } - [ProtoMember(4)] public OidbSvcTrpcTcp0x9154_1ResponseContent SpecialMagicFace { get; set; } + [ProtoMember(4)] public OidbSvcTrpcTcp0x9154_1ResponsesMagicEmojiContent SpecialMagicFace { get; set; } } [ProtoContract] @@ -25,6 +25,20 @@ internal class OidbSvcTrpcTcp0x9154_1ResponseContent [ProtoMember(2)] public OidbSvcTrpcTcp0x9154_1ResponseContentResourceUrl? ResourceUrl { get; set; } } +[ProtoContract] +internal class OidbSvcTrpcTcp0x9154_1ResponsesMagicEmojiContent +{ + [ProtoMember(1)] public OidbSvcTrpcTcp0x9154_1ResponsesMagicEmojiContentList Field1 { get; set; } + + [ProtoMember(2)] public OidbSvcTrpcTcp0x9154_1ResponseContentResourceUrl? ResourceUrl { get; set; } +} + +[ProtoContract] +internal class OidbSvcTrpcTcp0x9154_1ResponsesMagicEmojiContentList +{ + [ProtoMember(2)] public OidbSvcTrpcTcp0x9154_1ResponseContentEmoji[] EmojiList { get; set; } +} + [ProtoContract] internal class OidbSvcTrpcTcp0x9154_1ResponseContentEmojiList { @@ -36,29 +50,29 @@ internal class OidbSvcTrpcTcp0x9154_1ResponseContentEmojiList [ProtoContract] internal class OidbSvcTrpcTcp0x9154_1ResponseContentEmoji { - [ProtoMember(1)] public string? QSid { get; set; } + [ProtoMember(1)] public string QSid { get; set; } [ProtoMember(2)] public string? QDes { get; set; } [ProtoMember(3)] public string? EMCode { get; set; } - [ProtoMember(4)] public string? QCid { get; set; } + [ProtoMember(4)] public int? QCid { get; set; } - [ProtoMember(5)] public string? AniStickerType { get; set; } + [ProtoMember(5)] public int? AniStickerType { get; set; } - [ProtoMember(6)] public string? AniStickerPackId { get; set; } + [ProtoMember(6)] public int? AniStickerPackId { get; set; } - [ProtoMember(7)] public string? AniStickerId { get; set; } + [ProtoMember(7)] public int? AniStickerId { get; set; } [ProtoMember(8)] public OidbSvcTrpcTcp0x9154_1ResponseContentResourceUrl? Url { get; set; } - [ProtoMember(9)] public string[]? EmojiNameAilas { get; set; } + [ProtoMember(9)] public string[]? EmojiNameAlias { get; set; } - [ProtoMember(10)] public string? Unknown10 { get; set; } + [ProtoMember(10)] public int? Unknown10 { get; set; } - [ProtoMember(13)] public string? AniStickerWidth { get; set; } + [ProtoMember(13)] public int? AniStickerWidth { get; set; } - [ProtoMember(14)] public string? AniStickerHeight { get; set; } + [ProtoMember(14)] public int? AniStickerHeight { get; set; } } [ProtoContract] diff --git a/Lagrange.Core/Internal/Service/Action/JoinEmojiChainService.cs b/Lagrange.Core/Internal/Service/Action/JoinEmojiChainService.cs new file mode 100644 index 000000000..46f92ca79 --- /dev/null +++ b/Lagrange.Core/Internal/Service/Action/JoinEmojiChainService.cs @@ -0,0 +1,41 @@ +using Lagrange.Core.Common; +using Lagrange.Core.Internal.Event; +using Lagrange.Core.Internal.Event.Action; +using Lagrange.Core.Internal.Packets.Service.Oidb; +using Lagrange.Core.Internal.Packets.Service.Oidb.Request; +using Lagrange.Core.Utility.Extension; +using ProtoBuf; + +namespace Lagrange.Core.Internal.Service.Action; + +[EventSubscribe(typeof(GroupJoinEmojiChainEvent))] +[EventSubscribe(typeof(FriendJoinEmojiChainEvent))] +[Service("OidbSvcTrpcTcp.0x90ee_1")] +internal class FetchClientKeyService : BaseService +{ + protected override bool Build(JoinEmojiChainEvent input, BotKeystore keystore, BotAppInfo appInfo, + BotDeviceInfo device, out Span output, out List>? extraPackets) + { + var packet = new OidbSvcTrpcTcpBase(new OidbSvcTrpcTcp0x90EE_1 + { + FaceId = input.TargetFaceId, + TargetMsgSeq = input.TargetMessageSeq, + TargetMsgSeq_2 = input.TargetMessageSeq, + Field4 = input.GroupUin == null ? 1 : 2, + TargetGroupId = input.GroupUin, + TargetUid = input.FriendUid, + }); + output = packet.Serialize(); + extraPackets = null; + return true; + } + + protected override bool Parse(Span input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, + out JoinEmojiChainEvent output, out List? extraEvents) + { + var payload = Serializer.Deserialize>(input); + output = JoinEmojiChainEvent.Result((int)payload.ErrorCode); + extraEvents = null; + return true; + } +} \ No newline at end of file diff --git a/Lagrange.Core/Internal/Service/System/FetchFullSysFacesService.cs b/Lagrange.Core/Internal/Service/System/FetchFullSysFacesService.cs new file mode 100644 index 000000000..681c12cc5 --- /dev/null +++ b/Lagrange.Core/Internal/Service/System/FetchFullSysFacesService.cs @@ -0,0 +1,68 @@ +using Lagrange.Core.Common; +using Lagrange.Core.Common.Entity; +using Lagrange.Core.Internal.Event; +using Lagrange.Core.Internal.Event.System; +using Lagrange.Core.Internal.Packets.Service.Oidb; +using Lagrange.Core.Internal.Packets.Service.Oidb.Request; +using Lagrange.Core.Internal.Packets.Service.Oidb.Response; +using Lagrange.Core.Utility.Extension; +using ProtoBuf; + +namespace Lagrange.Core.Internal.Service.System; + +// TODO: onebot11 API (? +[EventSubscribe(typeof(FetchFullSysFacesEvent))] +[Service("OidbSvcTrpcTcp.0x9154_1")] +internal class FetchFullSysFacesService : BaseService +{ + protected override bool Build(FetchFullSysFacesEvent input, BotKeystore keystore, BotAppInfo appInfo, + BotDeviceInfo device, out Span output, out List>? extraPackets) + { + var packet = new OidbSvcTrpcTcpBase(new OidbSvcTrpcTcp0x9154_1 + { + Field1 = 0, + Field2 = 7, + Field3 = "0", + }); + + output = packet.Serialize(); + extraPackets = null; + return true; + } + + protected override bool Parse(Span input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, + out FetchFullSysFacesEvent output, out List? extraEvents) + { + var packet = Serializer.Deserialize>(input); + var response = packet.Body; + + var emojiPackList = new[] { response.CommonFace, response.SpecialBigFace } + .SelectMany(content => content.EmojiList) + .Select( + emojiList => new SysFacePackEntry( + emojiList.EmojiPackName, emojiList.EmojiDetail.Select( + emoji => new SysFaceEntry( + emoji.QSid, emoji.QDes, emoji.EMCode, emoji.QCid, emoji.AniStickerType, + emoji.AniStickerPackId, emoji.AniStickerId, emoji.Url?.BaseUrl, + emoji.EmojiNameAlias, emoji.AniStickerWidth, emoji.AniStickerHeight + ) + ).ToArray() + ) + ).ToList(); + + var magicFaceList = response.SpecialMagicFace.Field1.EmojiList.Select( + emoji => new SysFaceEntry( + emoji.QSid, emoji.QDes, emoji.EMCode, emoji.QCid, emoji.AniStickerType, + emoji.AniStickerPackId, emoji.AniStickerId, emoji.Url?.BaseUrl, + emoji.EmojiNameAlias, emoji.AniStickerWidth, emoji.AniStickerHeight + ) + ).ToList(); + + var magicFacePackEntry = new SysFacePackEntry("MagicFace", magicFaceList.ToArray()); + emojiPackList.Add(magicFacePackEntry); + + output = FetchFullSysFacesEvent.Result((int)packet.ErrorCode, emojiPackList); + extraEvents = null; + return true; + } +} \ No newline at end of file diff --git a/Lagrange.Core/Message/Entity/FaceEntity.cs b/Lagrange.Core/Message/Entity/FaceEntity.cs index 03ddbd311..941f1b6d8 100644 --- a/Lagrange.Core/Message/Entity/FaceEntity.cs +++ b/Lagrange.Core/Message/Entity/FaceEntity.cs @@ -1,3 +1,4 @@ +using Lagrange.Core.Common.Entity; using Lagrange.Core.Internal.Packets.Message.Element; using Lagrange.Core.Internal.Packets.Message.Element.Implementation; using Lagrange.Core.Internal.Packets.Message.Element.Implementation.Extra; @@ -10,11 +11,13 @@ public class FaceEntity : IMessageEntity { public ushort FaceId { get; set; } - public bool IsLargeFace { get; set; } + public bool? IsLargeFace { get; set; } + + public SysFaceEntry? SysFaceEntry { get; set; } public FaceEntity() { } - public FaceEntity(ushort faceId, bool isLargeFace) + public FaceEntity(ushort faceId, bool? isLargeFace) { FaceId = faceId; IsLargeFace = isLargeFace; @@ -22,17 +25,17 @@ public FaceEntity(ushort faceId, bool isLargeFace) IEnumerable IMessageEntity.PackElement() { - if (IsLargeFace) + if (IsLargeFace ?? false) { var qBigFace = new QBigFaceExtra { - AniStickerPackId = "1", - AniStickerId = "8", + AniStickerPackId = SysFaceEntry?.AniStickerPackId.ToString() ?? "1", + AniStickerId = SysFaceEntry?.AniStickerId.ToString() ?? "8", FaceId = FaceId, Field4 = 1, - AniStickerType = 1, + AniStickerType = SysFaceEntry?.AniStickerType ?? 1, Field6 = "", - Preview = "", + Preview = SysFaceEntry?.QDes ?? "", Field9 = 1 }; using var stream = new MemoryStream(); @@ -45,7 +48,7 @@ IEnumerable IMessageEntity.PackElement() { ServiceType = 37, PbElem = stream.ToArray(), - BusinessType = 1 + BusinessType = (uint)(SysFaceEntry?.AniStickerType ?? 1) } } }; @@ -56,8 +59,8 @@ IEnumerable IMessageEntity.PackElement() var qSmallFace = new QSmallFaceExtra { FaceId = FaceId, - Text = "", - CompatText = "" + Text = SysFaceEntry?.QDes ?? "", + CompatText = SysFaceEntry?.QDes ?? "" }; using var stream = new MemoryStream(); Serializer.Serialize(stream, qSmallFace); @@ -69,7 +72,7 @@ IEnumerable IMessageEntity.PackElement() { ServiceType = 33, PbElem = stream.ToArray(), - BusinessType = 1 + BusinessType = (uint)(SysFaceEntry?.AniStickerType ?? 1) } } }; @@ -103,5 +106,5 @@ IEnumerable IMessageEntity.PackElement() return null; } - public string ToPreviewString() => $"[Face][{(IsLargeFace ? "Large" : "Small")}]: {FaceId}"; + public string ToPreviewString() => $"[Face][{(IsLargeFace ?? false ? "Large" : "Small")}]: {FaceId}"; } \ No newline at end of file diff --git a/Lagrange.Core/Message/MessageBuilder.cs b/Lagrange.Core/Message/MessageBuilder.cs index 5bf5fc34d..a20a5cd3b 100644 --- a/Lagrange.Core/Message/MessageBuilder.cs +++ b/Lagrange.Core/Message/MessageBuilder.cs @@ -102,7 +102,7 @@ public MessageBuilder Mention(uint target, string? display = null) /// /// The id of emoji /// Is the emoji large - public MessageBuilder Face(ushort id, bool isLarge = false) + public MessageBuilder Face(ushort id, bool? isLarge = false) { var faceEntity = new FaceEntity(id, isLarge); _chain.Add(faceEntity); diff --git a/Lagrange.OneBot/Core/Entity/Action/OneBotGroupJoinEmojiChain.cs b/Lagrange.OneBot/Core/Entity/Action/OneBotGroupJoinEmojiChain.cs new file mode 100644 index 000000000..9adf71032 --- /dev/null +++ b/Lagrange.OneBot/Core/Entity/Action/OneBotGroupJoinEmojiChain.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; +namespace Lagrange.OneBot.Core.Entity.Action; + +public class OneBotGroupJoinEmojiChain +{ + [JsonPropertyName("group_id")] public uint GroupId { get; set; } + + [JsonPropertyName("message_id")] public int MessageId { get; set; } + + [JsonPropertyName("emoji_id")] public uint EmojiId { get; set; } +} \ No newline at end of file diff --git a/Lagrange.OneBot/Core/Entity/Action/OneBotPrivateJoinEmojiChain.cs b/Lagrange.OneBot/Core/Entity/Action/OneBotPrivateJoinEmojiChain.cs new file mode 100644 index 000000000..47b44fd05 --- /dev/null +++ b/Lagrange.OneBot/Core/Entity/Action/OneBotPrivateJoinEmojiChain.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; +namespace Lagrange.OneBot.Core.Entity.Action; + +public class OneBotPrivateJoinEmojiChain +{ + [JsonPropertyName("user_id")] public uint UserId { get; set; } + + [JsonPropertyName("message_id")] public int MessageId { get; set; } + + [JsonPropertyName("emoji_id")] public uint EmojiId { get; set; } +} \ No newline at end of file diff --git a/Lagrange.OneBot/Core/Operation/Generic/FriendJoinEmojiChainOperation.cs b/Lagrange.OneBot/Core/Operation/Generic/FriendJoinEmojiChainOperation.cs new file mode 100644 index 000000000..e6b17db93 --- /dev/null +++ b/Lagrange.OneBot/Core/Operation/Generic/FriendJoinEmojiChainOperation.cs @@ -0,0 +1,27 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using Lagrange.Core; +using Lagrange.Core.Message; +using Lagrange.Core.Common.Interface.Api; +using Lagrange.OneBot.Core.Entity.Action; +using Lagrange.OneBot.Core.Operation.Converters; +using Lagrange.OneBot.Database; +using LiteDB; + +namespace Lagrange.OneBot.Core.Operation.Generic; + + +[Operation(".join_friend_emoji_chain")] +public class FriendJoinEmojiChainOperation(LiteDatabase database) : IOperation +{ + public async Task HandleOperation(BotContext context, JsonNode? payload) + { + if (payload.Deserialize(SerializerOptions.DefaultOptions) is { } data) + { + var message = (MessageChain)database.GetCollection().FindById(data.MessageId); + bool res = await context.FriendJoinEmojiChain(data.UserId, data.EmojiId, message.Sequence); + return new OneBotResult(null, res ? 0 : -1, res ? "ok" : "failed"); + } + throw new Exception(); + } +} diff --git a/Lagrange.OneBot/Core/Operation/Generic/GroupJoinEmojiChainOperation.cs b/Lagrange.OneBot/Core/Operation/Generic/GroupJoinEmojiChainOperation.cs new file mode 100644 index 000000000..71638e322 --- /dev/null +++ b/Lagrange.OneBot/Core/Operation/Generic/GroupJoinEmojiChainOperation.cs @@ -0,0 +1,27 @@ +using System.Text.Json; +using System.Text.Json.Nodes; +using Lagrange.Core; +using Lagrange.Core.Message; +using Lagrange.Core.Common.Interface.Api; +using Lagrange.OneBot.Core.Entity.Action; +using Lagrange.OneBot.Core.Operation.Converters; +using Lagrange.OneBot.Database; +using LiteDB; + +namespace Lagrange.OneBot.Core.Operation.Generic; + + +[Operation(".join_group_emoji_chain")] +public class GroupJoinEmojiChainOperation(LiteDatabase database) : IOperation +{ + public async Task HandleOperation(BotContext context, JsonNode? payload) + { + if (payload.Deserialize(SerializerOptions.DefaultOptions) is { } data) + { + var message = (MessageChain)database.GetCollection().FindById(data.MessageId); + bool res = await context.GroupJoinEmojiChain(data.GroupId, data.EmojiId, message.Sequence); + return new OneBotResult(null, res ? 0 : -1, res ? "ok" : "failed"); + } + throw new Exception(); + } +} \ No newline at end of file diff --git a/Lagrange.OneBot/Message/Entity/FaceSegment.cs b/Lagrange.OneBot/Message/Entity/FaceSegment.cs index 3e2f5d2cc..4fa52beea 100644 --- a/Lagrange.OneBot/Message/Entity/FaceSegment.cs +++ b/Lagrange.OneBot/Message/Entity/FaceSegment.cs @@ -10,6 +10,9 @@ public partial class FaceSegment(int id) public FaceSegment() : this(0) { } [JsonPropertyName("id")] [CQProperty] public string Id { get; set; } = id.ToString(); + + [JsonPropertyName("large")] [CQProperty] public bool? IsLarge { get; set; } + } [SegmentSubscriber(typeof(FaceEntity), "face")] @@ -19,7 +22,7 @@ public partial class FaceSegment : SegmentBase public override void Build(MessageBuilder builder, SegmentBase segment) { - if (segment is FaceSegment faceSegment) builder.Face(ushort.Parse(faceSegment.Id)); + if (segment is FaceSegment faceSegment) builder.Face(ushort.Parse(faceSegment.Id), faceSegment.IsLarge); } public override SegmentBase? FromEntity(MessageChain chain, IMessageEntity entity) From 1700f8b2ea7360aee00645fb008a613af66b750b Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Tue, 22 Oct 2024 15:08:57 +0800 Subject: [PATCH 6/7] [Core] Always send small face by default --- .../Internal/Context/Logic/Implementation/MessagingLogic.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs b/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs index 690d8a188..4581d2ce5 100644 --- a/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs +++ b/Lagrange.Core/Internal/Context/Logic/Implementation/MessagingLogic.cs @@ -386,7 +386,6 @@ private async Task ResolveOutgoingChain(MessageChain chain) case FaceEntity face: { var cache = Collection.Business.CachingLogic; - face.IsLargeFace ??= await cache.GetCachedIsSuperFaceId(face.FaceId); face.SysFaceEntry ??= await cache.GetCachedFaceEntity(face.FaceId); break; } From ca2792c656d29380cae25985cefc5fe890cd451e Mon Sep 17 00:00:00 2001 From: pk5ls20 Date: Tue, 22 Oct 2024 15:29:30 +0800 Subject: [PATCH 7/7] [Core] resolve https://github.com/LagrangeDev/Lagrange.Core/pull/618#discussion_r1810102549 & https://github.com/LagrangeDev/Lagrange.Core/pull/618#discussion_r1810103474 --- .../Logic/Implementation/CachingLogic.cs | 3 +-- .../Logic/Implementation/OperationLogic.cs | 22 ++++++------------- .../Service/Action/JoinEmojiChainService.cs | 2 +- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/Lagrange.Core/Internal/Context/Logic/Implementation/CachingLogic.cs b/Lagrange.Core/Internal/Context/Logic/Implementation/CachingLogic.cs index cedf4bdfd..3fbafcdb7 100644 --- a/Lagrange.Core/Internal/Context/Logic/Implementation/CachingLogic.cs +++ b/Lagrange.Core/Internal/Context/Logic/Implementation/CachingLogic.cs @@ -47,8 +47,7 @@ public override Task Incoming(ProtocolEvent e) { return e switch { - GroupSysDecreaseEvent groupSysDecreaseEvent when groupSysDecreaseEvent.MemberUid != Collection.Keystore.Uid - => CacheUid(groupSysDecreaseEvent.GroupUin, true), + GroupSysDecreaseEvent groupSysDecreaseEvent when groupSysDecreaseEvent.MemberUid != Collection.Keystore.Uid => CacheUid(groupSysDecreaseEvent.GroupUin, true), GroupSysIncreaseEvent groupSysIncreaseEvent => CacheUid(groupSysIncreaseEvent.GroupUin, true), GroupSysAdminEvent groupSysAdminEvent => CacheUid(groupSysAdminEvent.GroupUin, true), _ => Task.CompletedTask, diff --git a/Lagrange.Core/Internal/Context/Logic/Implementation/OperationLogic.cs b/Lagrange.Core/Internal/Context/Logic/Implementation/OperationLogic.cs index a6edf5e61..1d1ce7796 100644 --- a/Lagrange.Core/Internal/Context/Logic/Implementation/OperationLogic.cs +++ b/Lagrange.Core/Internal/Context/Logic/Implementation/OperationLogic.cs @@ -212,7 +212,6 @@ public async Task> FetchGroupFSList(uint groupUin, string targ if (((GroupFSListEvent)events[0]).IsEnd) break; startIndex += 20; } - return entries; } @@ -223,8 +222,7 @@ public async Task FetchGroupFSDownload(uint groupUin, string fileId) return $"{((GroupFSDownloadEvent)events[0]).FileUrl}{fileId}"; } - public async Task<(int, string)> GroupFSMove(uint groupUin, string fileId, string parentDirectory, - string targetDirectory) + public async Task<(int, string)> GroupFSMove(uint groupUin, string fileId, string parentDirectory, string targetDirectory) { var groupFSMoveEvent = GroupFSMoveEvent.Create(groupUin, fileId, parentDirectory, targetDirectory); var events = await Collection.Business.SendEvent(groupFSMoveEvent); @@ -273,8 +271,7 @@ public Task GroupFSUpload(uint groupUin, FileEntity fileEntity, string tar { try { - return FileUploader.UploadGroup(Collection, MessageBuilder.Group(groupUin).Build(), fileEntity, - targetDirectory); + return FileUploader.UploadGroup(Collection, MessageBuilder.Group(groupUin).Build(), fileEntity, targetDirectory); } catch { @@ -327,8 +324,7 @@ public async Task RecallFriendMessage(uint friendUin, MessageResult result if (result.Sequence == null) return false; if (await Collection.Business.CachingLogic.ResolveUid(null, friendUin) is not { } uid) return false; - var recallMessageEvent = RecallFriendMessageEvent.Create(uid, result.ClientSequence, result.Sequence ?? 0, - (uint)(result.MessageId & uint.MaxValue), result.Timestamp); + var recallMessageEvent = RecallFriendMessageEvent.Create(uid, result.ClientSequence, result.Sequence ?? 0, (uint)(result.MessageId & uint.MaxValue), result.Timestamp); var events = await Collection.Business.SendEvent(recallMessageEvent); return events.Count != 0 && ((RecallFriendMessageEvent)events[0]).ResultCode == 0; } @@ -338,8 +334,7 @@ public async Task RecallFriendMessage(MessageChain chain) if (await Collection.Business.CachingLogic.ResolveUid(null, chain.TargetUin) is not { } uid) return false; uint timestamp = (uint)new DateTimeOffset(chain.Time).ToUnixTimeSeconds(); - var recallMessageEvent = RecallFriendMessageEvent.Create(uid, chain.ClientSequence, chain.Sequence, - (uint)(chain.MessageId & uint.MaxValue), timestamp); + var recallMessageEvent = RecallFriendMessageEvent.Create(uid, chain.ClientSequence, chain.Sequence, (uint)(chain.MessageId & uint.MaxValue), timestamp); var events = await Collection.Business.SendEvent(recallMessageEvent); return events.Count != 0 && ((RecallFriendMessageEvent)events[0]).ResultCode == 0; } @@ -355,8 +350,7 @@ public async Task RecallFriendMessage(MessageChain chain) foreach (var result in resolved) { - var uins = await Task.WhenAll(ResolveUid(result.InvitorMemberUid), ResolveUid(result.TargetMemberUid), - ResolveUid(result.OperatorUid)); + var uins = await Task.WhenAll(ResolveUid(result.InvitorMemberUid), ResolveUid(result.TargetMemberUid), ResolveUid(result.OperatorUid)); uint invitorUin = uins[0]; uint targetUin = uins[1]; uint operatorUin = uins[2]; @@ -493,8 +487,7 @@ public async Task SetGroupRequest(uint groupUin, ulong sequence, uint type return results.Count != 0 && results[0].ResultCode == 0; } - public async Task SetGroupFilteredRequest(uint groupUin, ulong sequence, uint type, bool accept, - string reason) + public async Task SetGroupFilteredRequest(uint groupUin, ulong sequence, uint type, bool accept, string reason) { var inviteEvent = SetGroupFilteredRequestEvent.Create(accept, groupUin, sequence, type, reason); var results = await Collection.Business.SendEvent(inviteEvent); @@ -671,8 +664,7 @@ public async Task SetAvatar(ImageEntity avatar) var ticket = ((HighwayUrlEvent)highwayUrlResults[0]).SigSession; var md5 = avatar.ImageStream.Value.Md5().UnHex(); - return await Collection.Highway.UploadSrcByStreamAsync(90, avatar.ImageStream.Value, ticket, md5, - Array.Empty()); + return await Collection.Highway.UploadSrcByStreamAsync(90, avatar.ImageStream.Value, ticket, md5, Array.Empty()); } public async Task GroupSetAvatar(uint groupUin, ImageEntity avatar) diff --git a/Lagrange.Core/Internal/Service/Action/JoinEmojiChainService.cs b/Lagrange.Core/Internal/Service/Action/JoinEmojiChainService.cs index 46f92ca79..4364dcd4d 100644 --- a/Lagrange.Core/Internal/Service/Action/JoinEmojiChainService.cs +++ b/Lagrange.Core/Internal/Service/Action/JoinEmojiChainService.cs @@ -11,7 +11,7 @@ namespace Lagrange.Core.Internal.Service.Action; [EventSubscribe(typeof(GroupJoinEmojiChainEvent))] [EventSubscribe(typeof(FriendJoinEmojiChainEvent))] [Service("OidbSvcTrpcTcp.0x90ee_1")] -internal class FetchClientKeyService : BaseService +internal class JoinEmojiChainService : BaseService { protected override bool Build(JoinEmojiChainEvent input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, out Span output, out List>? extraPackets)