From 79f6f45bc158a430f5dbb98fd6cb0a70f4571056 Mon Sep 17 00:00:00 2001 From: edwinQQQ Date: Mon, 18 Aug 2025 14:01:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=A4=BC=E7=89=A9=E5=8A=A8?= =?UTF-8?q?=E7=94=BB=E5=A4=84=E7=90=86=E6=97=A5=E5=BF=97=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96=E4=BA=86=20GiftAn?= =?UTF-8?q?imationManager=20=E5=92=8C=20GiftComboManager=20=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E8=BF=9E=E5=87=BB=E8=AE=A1=E6=95=B0=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E7=A1=AE=E4=BF=9D=E8=BF=9E=E5=87=BB=E8=AE=A1=E6=95=B0?= =?UTF-8?q?=E7=9A=84=E6=9C=89=E6=95=88=E6=80=A7=E5=92=8C=E5=87=86=E7=A1=AE?= =?UTF-8?q?=E6=80=A7=E3=80=82=E5=90=8C=E6=97=B6=EF=BC=8C=E5=A2=9E=E5=BC=BA?= =?UTF-8?q?=E4=BA=86=E6=97=A5=E5=BF=97=E8=BE=93=E5=87=BA=EF=BC=8C=E4=BE=BF?= =?UTF-8?q?=E4=BA=8E=E8=B0=83=E8=AF=95=E5=92=8C=E7=9B=91=E6=8E=A7=E5=8A=A8?= =?UTF-8?q?=E7=94=BB=E5=A4=84=E7=90=86=E7=8A=B6=E6=80=81=EF=BC=8C=E6=8F=90?= =?UTF-8?q?=E5=8D=87=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOC/log.txt | 35 +++ .../View/AnimationView/GiftAnimationManager.m | 64 ++++-- .../View/AnimationView/RoomAnimationView.m | 20 ++ .../View/SendGiftView/GiftComboManager.h | 5 + .../View/SendGiftView/GiftComboManager.m | 211 ++++++++++++++++-- .../View/SendGiftView/View/GiftComboView.m | 16 +- .../View/SendGiftView/View/XPSendGiftView.m | 42 +++- .../Banner手势优化实施总结.md | 0 .../Email-VerificationCode-Login-Flow.md | 0 .../OAuth_Ticket_API_Documentation.md | 0 ...PublicRoomMessageForward_Implementation.md | 6 + 11 files changed, 359 insertions(+), 40 deletions(-) create mode 100644 DOC/log.txt rename Banner手势优化实施总结.md => docs/Banner手势优化实施总结.md (100%) rename Email-VerificationCode-Login-Flow.md => docs/Email-VerificationCode-Login-Flow.md (100%) rename OAuth_Ticket_API_Documentation.md => docs/OAuth_Ticket_API_Documentation.md (100%) rename PublicRoomMessageForward_Implementation.md => docs/PublicRoomMessageForward_Implementation.md (99%) diff --git a/DOC/log.txt b/DOC/log.txt new file mode 100644 index 00000000..45642679 --- /dev/null +++ b/DOC/log.txt @@ -0,0 +1,35 @@ +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 0 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 3 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 4 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 5 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 6 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 7 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 8 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 9 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 10 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 11 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 12 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 13 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 14 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 15 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 16 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 17 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 18 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 19 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 20 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 21 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 22 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 23 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 24 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 25 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 26 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 27 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 28 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 29 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 30 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 31 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 32 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 33 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 34 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 35 +-[GiftAnimationManager processNextGift]_block_invoke [Line 93][Combo effect] 🎬 开始处理动画 - giftId: 2263, combo: 0 \ No newline at end of file diff --git a/YuMi/Modules/YMRoom/View/AnimationView/GiftAnimationManager.m b/YuMi/Modules/YMRoom/View/AnimationView/GiftAnimationManager.m index 0e688c72..da66b36c 100644 --- a/YuMi/Modules/YMRoom/View/AnimationView/GiftAnimationManager.m +++ b/YuMi/Modules/YMRoom/View/AnimationView/GiftAnimationManager.m @@ -77,43 +77,67 @@ } - (void)processNextGift { - if (self.giftQueue.count == 0) { - [self stopGiftQueue]; - return; - } - - GiftReceiveInfoModel *giftInfo = self.giftQueue.firstObject; - if (!giftInfo) return; - - // 安全地移除第一个元素 dispatch_async(self.queue, ^{ - if (self.giftQueue.count > 0) { - [self.giftQueue xpSafeRemoveObjectAtIndex:0]; + if (self.giftQueue.count == 0) { + NSLog(@"[Combo effect] 📭 动画队列为空,停止处理"); + [self stopGiftQueue]; + return; } - }); - - @kWeakify(self); - dispatch_async(dispatch_get_main_queue(), ^{ - @kStrongify(self); - if (self) { - [self distributeGiftAnimation:giftInfo]; + + GiftReceiveInfoModel *giftInfo = self.giftQueue.firstObject; + if (!giftInfo) { + NSLog(@"[Combo effect] ⚠️ 队列第一个元素为空,跳过处理"); + return; } + + // 检查并修复连击计数 + if (giftInfo.comboCount < 1) { + NSLog(@"[Combo effect] 🚨 动画处理中检测到连击计数异常 - comboCount: %ld", (long)giftInfo.comboCount); + giftInfo.comboCount = 1; + NSLog(@"[Combo effect] 🔧 修复动画连击计数为 1"); + } + + NSLog(@"[Combo effect] 🎬 开始处理动画 - giftId: %ld, combo: %ld", (long)giftInfo.gift.giftId, (long)giftInfo.comboCount); + + // 在同一线程中移除元素 + [self.giftQueue xpSafeRemoveObjectAtIndex:0]; + NSLog(@"[Combo effect] 📊 移除后动画队列数量: %ld", (long)self.giftQueue.count); + + @kWeakify(self); + dispatch_async(dispatch_get_main_queue(), ^{ + @kStrongify(self); + if (self) { + [self distributeGiftAnimation:giftInfo]; + } else { + NSLog(@"[Combo effect] ⚠️ self已释放,跳过动画分发"); + } + }); }); } - (void)distributeGiftAnimation:(GiftReceiveInfoModel *)giftInfo { + NSLog(@"[Combo effect] 🎯 开始分发动画 - uid: %@", giftInfo.uid); + NSArray *targetUids = [self resolveTargetUids:giftInfo]; + NSLog(@"[Combo effect] 🎯 目标用户数量: %ld", (long)targetUids.count); + CGPoint startPoint = CGPointZero; BOOL isComboAnimation = [self shouldUseComboAnimationForSender:giftInfo.uid]; + NSLog(@"[Combo effect] 🎯 是否使用连击动画: %@", isComboAnimation ? @"YES" : @"NO"); + if (isComboAnimation) { startPoint = [self comboAnimationStartPoint]; + NSLog(@"[Combo effect] 🎯 使用连击动画起点: %@", NSStringFromCGPoint(startPoint)); } else { startPoint = [self calculateAnimationPoint:giftInfo.uid isEndPoint:NO]; + NSLog(@"[Combo effect] 🎯 使用普通动画起点: %@", NSStringFromCGPoint(startPoint)); } NSTimeInterval delay = isComboAnimation ? self.comboAnimationDelay : self.standardAnimationDelay; + NSLog(@"[Combo effect] 🎯 动画延迟时间: %.2f", delay); for (NSString *targetUid in targetUids) { CGPoint endPoint = [self calculateAnimationPoint:targetUid isEndPoint:YES]; + NSLog(@"[Combo effect] 🎯 为目标用户 %@ 创建动画 - 终点: %@", targetUid, NSStringFromCGPoint(endPoint)); [self scheduleAnimationWithDelay:delay giftInfo:giftInfo.gift startPoint:startPoint @@ -206,11 +230,15 @@ - (void)enqueueGift:(GiftReceiveInfoModel *)giftInfo { if (!giftInfo) { + NSLog(@"[Combo effect] ⚠️ 礼物信息为空,跳过动画队列"); return; } + NSLog(@"[Combo effect] 🎬 添加礼物到动画队列 - giftId: %ld, combo: %ld", (long)giftInfo.gift.giftId, (long)giftInfo.comboCount); + dispatch_async(self.queue, ^{ [self.giftQueue addObject:giftInfo]; + NSLog(@"[Combo effect] 📊 动画队列当前数量: %ld", (long)self.giftQueue.count); [self startGiftQueue]; }); } diff --git a/YuMi/Modules/YMRoom/View/AnimationView/RoomAnimationView.m b/YuMi/Modules/YMRoom/View/AnimationView/RoomAnimationView.m index 2154c73e..e5007379 100644 --- a/YuMi/Modules/YMRoom/View/AnimationView/RoomAnimationView.m +++ b/YuMi/Modules/YMRoom/View/AnimationView/RoomAnimationView.m @@ -1722,9 +1722,26 @@ UIGestureRecognizerDelegate return; } + NSLog(@"[Combo effect] 📨 收到礼物消息 - second: %ld", (long)attachment.second); GiftReceiveInfoModel * receiveInfo = [GiftReceiveInfoModel modelWithJSON:attachment.data]; [receiveInfo giftDataAlignment]; + // 检查并修复连击计数 + if (receiveInfo.comboCount < 1) { + NSLog(@"[Combo effect] 🚨 收到云信消息中连击计数异常 - comboCount: %ld", (long)receiveInfo.comboCount); + // 尝试从 attachment.data 中获取正确的连击计数 + NSNumber *dataComboCount = attachment.data[@"comboCount"]; + if (dataComboCount && [dataComboCount integerValue] >= 1) { + NSLog(@"[Combo effect] 🔧 从 attachment.data 修复连击计数 - 修复为: %@", dataComboCount); + receiveInfo.comboCount = [dataComboCount integerValue]; + } else { + NSLog(@"[Combo effect] 🔧 设置默认连击计数为 1"); + receiveInfo.comboCount = 1; + } + } + + NSLog(@"[Combo effect] 📨 礼物消息解析完成 - giftId: %ld, combo: %ld, uid: %@", (long)receiveInfo.gift.giftId, (long)receiveInfo.comboCount, receiveInfo.uid); + receiveInfo.isLuckyBagGift = (attachment.second == Custom_Message_Sub_Gift_LuckySend || attachment.second == Custom_Message_Sub_AllMicroLuckySend || attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend); @@ -1776,6 +1793,7 @@ UIGestureRecognizerDelegate } if (receiveInfo.isLuckyBagGift) { + NSLog(@"[Combo effect] 🎁 处理福袋礼物"); [self receiveGiftHandleSendGiftAnimationWith:receiveInfo attachment:attachment]; [self _handleBagGift:receiveInfo]; @@ -1783,9 +1801,11 @@ UIGestureRecognizerDelegate if (receiveInfo.gift.notifyFull == 1 && attachment.second == Custom_Message_Sub_Gift_Send) { // 全服礼物,但由自己发送,不在此逻辑播放 + NSLog(@"[Combo effect] 🎁 全服礼物由自己发送,跳过播放"); return; } // 处理从位置 发送者 到 接受者 的礼物移动动画 + NSLog(@"[Combo effect] 🎁 处理普通礼物动画"); [self receiveGiftHandleSendGiftAnimationWith:receiveInfo attachment:attachment]; // 播放礼物动画(svga/mp4)(如果有的话) diff --git a/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.h b/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.h index 293e6d9d..99d0816d 100644 --- a/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.h +++ b/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.h @@ -70,6 +70,11 @@ NS_ASSUME_NONNULL_BEGIN - (NSInteger)loadTotalGiftNum; - (BOOL)isGiftCombing; +// 新增:连击状态检查方法 +- (BOOL)isComboStateValid; +- (NSDictionary *)getComboStateInfo; +- (void)printComboState; + - (NSString *)loadErrorMessage; - (void)receiveGiftInfoForDisplayComboFlags:(GiftReceiveInfoModel *)receiveInfo diff --git a/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.m b/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.m index d5255e0f..54448f10 100644 --- a/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.m +++ b/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.m @@ -112,16 +112,34 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific // 开始连击,重置 - (void)resetCombo { + NSLog(@"[Combo effect] 🔄 开始连击重置 - combo: %ld -> 1, enableCombo: %@, actionCallback: %@", + (long)self.combo, + self.enableCombo ? @"YES" : @"NO", + self.actionCallback ? @"可用" : @"为空"); + + // 确保连击计数正确重置为 1 _combo = 1; _errorMessage = @""; + + // 验证重置后的状态 + NSLog(@"[Combo effect] 🔍 重置后验证 - combo: %ld", (long)self.combo); + + // 检查是否应该显示连击面板 if (self.actionCallback && self.enableCombo) { + NSLog(@"[Combo effect] 📱 触发连击面板显示回调"); self.actionCallback(ComboAction_ShowPanel); self.isCombing = YES; + } else if (self.actionCallback && !self.enableCombo) { + NSLog(@"[Combo effect] ⚠️ enableCombo为NO,不显示连击面板"); + } else if (!self.actionCallback) { + NSLog(@"[Combo effect] ⚠️ actionCallback为空,不显示连击面板"); } if (self.handleRoomUIChanged) { + NSLog(@"[Combo effect] 🎮 隐藏房间UI元素"); self.handleRoomUIChanged(YES); } + NSLog(@"[Combo effect] ✅ 连击重置完成 - isCombing: %@", self.isCombing ? @"YES" : @"NO"); } - (void)registerActions:(void (^)(ComboActionType))action { @@ -131,32 +149,44 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific } - (void)forceRemove { + NSLog(@"[Combo effect] 🚨 触发forceRemove - combo: %ld, isCombing: %@", (long)self.combo, self.isCombing ? @"YES" : @"NO"); // 调用新的强制重置方法 [self forceBoomStateReset]; // 通知UI移除连击面板 if (self.actionCallback) { + NSLog(@"[Combo effect] 📱 触发连击面板移除回调"); self.actionCallback(ComboAction_RemovePanel); } } - (void)forceBoomStateReset { - NSLog(@"🚨 执行强制Boom连击状态重置"); + NSLog(@"[Combo effect] 🚨 执行强制Boom连击状态重置"); // 1. 立即停止所有定时器(无条件停止) + NSLog(@"[Combo effect] ⏰ 停止所有定时器"); [self forceStopAllTimers]; // 2. 清空所有队列 + NSLog(@"[Combo effect] 🗑️ 清空所有队列"); [self clearAllQueues]; // 3. 重置所有状态标志 + NSLog(@"[Combo effect] 🔄 重置状态标志 - isCombing: %@ -> NO", + self.isCombing ? @"YES" : @"NO"); self.isCombing = NO; - self.enableCombo = NO; - // 4. 清理回调 - self.actionCallback = nil; + // 注意:不重置 enableCombo,保持连击功能可用状态 + // self.enableCombo = NO; // 移除这行,保持连击功能可用 + + // 注意:不重置 combo 计数,保持连击计数的连续性 + // 连击计数应该在下次 resetCombo 时重置为 1 + + // 4. 注意:不清理 actionCallback,保持回调可用,以便重新进入连击状态 + // self.actionCallback = nil; // 移除这行,保持回调可用 // 5. 发送通知(优先级最高,通知所有相关组件) + NSLog(@"[Combo effect] 📢 发送强制重置通知"); dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] postNotificationName:kBoomStateForceResetNotification object:nil]; @@ -164,10 +194,14 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific // 6. 强制恢复UI(确保底部栏和侧栏显示) if (self.handleRoomUIChanged) { + NSLog(@"[Combo effect] 🎮 恢复房间UI元素"); dispatch_async(dispatch_get_main_queue(), ^{ self.handleRoomUIChanged(NO); }); } + NSLog(@"[Combo effect] ✅ 强制重置完成 - enableCombo保持: %@, actionCallback保持: %@", + self.enableCombo ? @"YES" : @"NO", + self.actionCallback ? @"可用" : @"为空"); } // 无条件停止定时器 @@ -193,17 +227,31 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific } - (NSInteger)loadComboCountFromSendGiftView { + @synchronized (self) { + if (!self.enableCombo) { + NSLog(@"[Combo effect] ❌ 连击未启用,返回计数0"); + return 0; + } - if (!self.enableCombo) { - return 0; + // 确保连击计数最少为 1 + if (self.combo < 1) { + NSLog(@"[Combo effect] ⚠️ 连击计数异常,重置为1 - 当前: %ld", (long)self.combo); + self.combo = 1; + } + + NSInteger temp = self.combo; + self.combo += 1; + NSLog(@"[Combo effect] 🔢 连击计数更新 - 当前: %ld -> 下次: %ld", (long)temp, (long)self.combo); + return temp; } - - NSInteger temp = self.combo; - self.combo += 1; - return temp; } - (NSInteger)loadComboCount { + // 确保连击计数最少为 1 + if (self.combo < 1) { + NSLog(@"[Combo effect] ⚠️ loadComboCount: 连击计数异常,重置为1 - 当前: %ld", (long)self.combo); + self.combo = 1; + } return self.combo; } @@ -212,14 +260,71 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific } - (BOOL)isGiftCombing { - return self.isCombing; + return self.isCombing && self.enableCombo; +} + +// 新增:检查连击状态是否有效 +- (BOOL)isComboStateValid { + @synchronized (self) { + return self.isCombing && + self.enableCombo && + self.combo > 0 && + self.giftInfo != nil && + self.sendGiftToUIDs.count > 0; + } +} + +// 新增:获取连击状态信息 +- (NSDictionary *)getComboStateInfo { + @synchronized (self) { + return @{ + @"isCombing": @(self.isCombing), + @"enableCombo": @(self.enableCombo), + @"combo": @(self.combo), + @"hasGiftInfo": @(self.giftInfo != nil), + @"targetCount": @(self.sendGiftToUIDs.count), + @"errorMessage": self.errorMessage ?: @"" + }; + } +} + +// 新增:打印当前连击状态(用于调试) +- (void)printComboState { + NSDictionary *stateInfo = [self getComboStateInfo]; + NSLog(@"[Combo effect] 📊 当前连击状态:"); + NSLog(@"[Combo effect] - isCombing: %@", [stateInfo[@"isCombing"] boolValue] ? @"YES" : @"NO"); + NSLog(@"[Combo effect] - enableCombo: %@", [stateInfo[@"enableCombo"] boolValue] ? @"YES" : @"NO"); + NSLog(@"[Combo effect] - combo: %@", stateInfo[@"combo"]); + NSLog(@"[Combo effect] - hasGiftInfo: %@", [stateInfo[@"hasGiftInfo"] boolValue] ? @"YES" : @"NO"); + NSLog(@"[Combo effect] - targetCount: %@", stateInfo[@"targetCount"]); + NSLog(@"[Combo effect] - errorMessage: %@", stateInfo[@"errorMessage"]); + + // 检查并修复连击计数异常 + [self validateAndFixComboCount]; +} + +// 新增:验证并修复连击计数 +- (void)validateAndFixComboCount { + @synchronized (self) { + if (self.combo < 1) { + NSLog(@"[Combo effect] 🚨 检测到连击计数异常,自动修复 - 当前: %ld -> 1", (long)self.combo); + self.combo = 1; + } + + if (self.combo > 1000) { + NSLog(@"[Combo effect] 🚨 检测到连击计数异常,自动修复 - 当前: %ld -> 100", (long)self.combo); + self.combo = 100; + } + } } #pragma mark - 处理飘屏逻辑 - (void)receiveGiftInfoForDisplayComboFlags:(GiftReceiveInfoModel *)receiveInfo container:(UIView *)container { + NSLog(@"[Combo effect] 🎪 收到连击飘屏请求 - combo: %ld, giftId: %ld", (long)receiveInfo.comboCount, (long)receiveInfo.gift.giftId); self.containerView = container; [self.giftComboQueue addObject:receiveInfo]; + NSLog(@"[Combo effect] 📊 连击飘屏队列数量: %ld", (long)self.giftComboQueue.count); [self startProcessingGiftComboFlagQueue]; } @@ -270,7 +375,9 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific } GiftReceiveInfoModel *receiveInfo = [self.giftComboQueue firstObject]; + NSLog(@"[Combo effect] 🎪 处理连击飘屏 - combo: %ld, giftId: %ld", (long)receiveInfo.comboCount, (long)receiveInfo.gift.giftId); [self.giftComboQueue xpSafeRemoveObjectAtIndex:0]; + NSLog(@"[Combo effect] 📊 移除后连击飘屏队列数量: %ld", (long)self.giftComboQueue.count); dispatch_async(dispatch_get_main_queue(), ^{ [self handleGiftInfo:receiveInfo]; }); @@ -471,6 +578,8 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific #pragma mark - Gift meta data - (void)enableToCombo:(BOOL)enable { + NSLog(@"[Combo effect] 🔧 设置连击功能状态 - enableCombo: %@ -> %@", + self.enableCombo ? @"YES" : @"NO", enable ? @"YES" : @"NO"); self.enableCombo = enable; } @@ -522,6 +631,8 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific #pragma mark - XPGiftPresenter - (void)sendGift { + NSLog(@"[Combo effect] 🎁 开始发送连击礼物 - combo: %ld, isCombing: %@", (long)self.combo, self.isCombing ? @"YES" : @"NO"); + NSString *allUIDs = @""; for (NSString *item in self.sendGiftToUIDs) { if (allUIDs.length > 0) { @@ -540,19 +651,25 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific @"roomUid":self.roomUID }; + NSLog(@"[Combo effect] 📦 添加礼物请求到队列 - giftId: %ld, targetUids: %@", (long)self.giftInfo.giftId, allUIDs); [self.requestQueue addObject:dic]; [self startProcessingQueue]; } - (void)handleSendGift:(NSDictionary *)dic { NSString *allUIDs = [dic objectForKey:@"targetUids"]; + NSString *giftId = [dic objectForKey:@"giftId"]; + NSLog(@"[Combo effect] 🌐 开始调用送礼API - giftId: %@, targetUids: %@", giftId, allUIDs); + @kWeakify(self); [Api requestSendGift:^(BaseModel * _Nullable data, NSInteger code, NSString * _Nullable msg) { @kStrongify(self); if (!self) { + NSLog(@"[Combo effect] ⚠️ self已释放,忽略API回调"); return; } if (code == 200) { + NSLog(@"[Combo effect] ✅ 送礼API成功 - giftId: %@, combo: %ld", giftId, (long)self.combo); GiftReceiveInfoModel *receive = [GiftReceiveInfoModel modelWithJSON:data.data]; receive.sourceType = [[dic objectForKey:@"giftSource"] integerValue]; receive.roomSendGiftType = [[dic objectForKey:@"giftType"] integerValue]; @@ -564,9 +681,13 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific @"Price": @(receive.gift.goldPrice * receive.giftNum * array.count), @"isFromWinning":@(NO)}]; } else { + NSLog(@"[Combo effect] ❌ 送礼API失败 - code: %ld, msg: %@", (long)code, msg); + // 区分错误类型,优化恢复策略 if (code > 500 && code < 600) { + // 服务器错误,可能是临时问题,保持连击状态 + NSLog(@"[Combo effect] 🔄 服务器错误,保持连击状态 - code: %ld", (long)code); #if DEBUG - self.errorMessage = [NSString stringWithFormat:@"Over Heat! - %@ ", msg]; + self.errorMessage = [NSString stringWithFormat:@"服务器繁忙,请稍后重试 - %@", msg]; #else self.errorMessage = @"Over Heat & try later"; dispatch_async(dispatch_get_global_queue(0, 0), ^{ @@ -583,10 +704,31 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific userInfo:logDic]]; }); #endif - } else { - self.errorMessage = msg; + // 临时错误,不重置连击状态,允许用户重试 + } else if (code == 31005) { + // 余额不足,需要重置连击状态 + NSLog(@"[Combo effect] 💰 余额不足,强制移除连击状态"); + self.errorMessage = YMLocalizedString(@"XPCandyTreeInsufficientBalanceView1"); [self forceRemove]; + } else if (code == 8535) { + // VIP等级不足,需要重置连击状态, 但不可能出现 + NSLog(@"[Combo effect] 👑 VIP等级不足,强制移除连击状态"); + self.errorMessage = @""; + [self forceRemove]; + } else { + // 其他错误,根据错误类型决定是否重置连击状态 + self.errorMessage = msg; + // 对于网络错误等临时问题,保持连击状态 + if (code >= 1000 && code < 2000) { + // 网络相关错误,保持连击状态 + NSLog(@"[Combo effect] 🌐 网络错误,保持连击状态 - code: %ld", (long)code); + } else { + // 其他错误,重置连击状态 + NSLog(@"[Combo effect] 🚨 其他错误,强制移除连击状态 - code: %ld", (long)code); + [self forceRemove]; + } } + if (self.actionCallback) { self.actionCallback(ComboAction_Error); } @@ -605,25 +747,51 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific - (void)handleSendGiftSuccess:(GiftReceiveInfoModel *)receive sourceData:(BaseModel *)response { - if (self.actionCallback) { - self.actionCallback(ComboAction_Combo_Count_Update); + NSLog(@"[Combo effect] 🎉 连击礼物发送成功 - 当前combo: %ld", (long)self.combo); + + // 验证连击计数有效性 + [self validateAndFixComboCount]; + + // 更新连击计数(连击面板点击时) + if (self.isCombing) { + NSLog(@"[Combo effect] 🔢 连击进行中,更新连击计数"); + if (self.actionCallback) { + self.actionCallback(ComboAction_Combo_Count_Update); + } } NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:response.data]; - [dic setObject:@(self.combo) forKey:@"comboCount"]; + + // 确保连击计数最少为 1 + NSInteger comboToSet = self.combo; + if (comboToSet < 1) { + NSLog(@"[Combo effect] 🚨 发送云信消息时连击计数异常,修复为 1 - 当前: %ld", (long)comboToSet); + comboToSet = 1; + } + + [dic setObject:@(comboToSet) forKey:@"comboCount"]; + + // 验证连击计数设置 + NSNumber *setComboCount = dic[@"comboCount"]; + NSLog(@"[Combo effect] 🔍 连击计数设置验证 - 设置值: %@, 当前combo: %ld", setComboCount, (long)self.combo); self.sendGiftReceiveInfo = receive; if (self.handleComboSuccess) { + NSLog(@"[Combo effect] 📨 调用连击成功回调,发送云信消息"); self.handleComboSuccess(receive, dic); } if (self.actionCallback) { self.actionCallback(ComboAction_Update_After_Send_Success); } + + NSLog(@"[Combo effect] ✅ 连击礼物处理完成"); } - (void)sendCustomMessage:(AttachmentModel *)attachment { + NSLog(@"[Combo effect] 📨 发送云信自定义消息 - combo: %ld", (long)self.combo); + NIMMessage *message = [[NIMMessage alloc]init]; NIMCustomObject *object = [[NIMCustomObject alloc] init]; object.attachment = attachment; @@ -640,7 +808,14 @@ NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotific //构造会话 NIMSession *session = [NIMSession session:self.sessionID type:NIMSessionTypeChatroom]; - [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:nil]; + NSError *error = nil; + [[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error]; + + if (error) { + NSLog(@"[Combo effect] ❌ 云信消息发送失败 - error: %@", error.localizedDescription); + } else { + NSLog(@"[Combo effect] ✅ 云信消息发送成功"); + } } diff --git a/YuMi/Modules/YMRoom/View/SendGiftView/View/GiftComboView.m b/YuMi/Modules/YMRoom/View/SendGiftView/View/GiftComboView.m index e6fa23ec..2b159efa 100644 --- a/YuMi/Modules/YMRoom/View/SendGiftView/View/GiftComboView.m +++ b/YuMi/Modules/YMRoom/View/SendGiftView/View/GiftComboView.m @@ -124,7 +124,10 @@ } - (void)updateCount { - NSString *countStr = [NSString stringWithFormat:@"x%ld", [[GiftComboManager sharedManager] loadComboCount]]; + // 在连击面板点击时,需要先更新连击计数 + NSInteger comboCount = [[GiftComboManager sharedManager] loadComboCountFromSendGiftView]; + NSLog(@"[Combo effect] 🔢 更新连击次数显示 - combo: %ld", (long)comboCount); + NSString *countStr = [NSString stringWithFormat:@"x%ld", comboCount]; NSShadow *shadow = [[NSShadow alloc] init]; shadow.shadowBlurRadius = 3; shadow.shadowColor = [UIColor colorWithRed:255/255.0 green:153./255.0 blue:0/255.0 alpha:1]; @@ -134,6 +137,9 @@ NSForegroundColorAttributeName: UIColorFromRGB(0xFFE07B), NSShadowAttributeName: shadow}]; self.comboCountLabel.attributedText = string; + + // 打印当前连击状态,确认计数正确 + [[GiftComboManager sharedManager] printComboState]; } - (void)stopTimer { @@ -203,19 +209,22 @@ } - (void)setupTimer { + NSLog(@"[Combo effect] ⏰ 设置连击倒计时"); @kWeakify(self); [self.countdownRingView setCompletionHandler:^{ @kStrongify(self); + NSLog(@"[Combo effect] ⏰ 连击倒计时结束,触发强制移除"); self.userInteractionEnabled = NO; [[GiftComboManager sharedManager] forceRemove]; }]; [self.countdownRingView startCountdown]; + NSLog(@"[Combo effect] ⏰ 连击倒计时已启动"); } - (void)handleTap { static BOOL isHandlingTap = NO; if (isHandlingTap) { -// NSLog(@"点击间隔过短,忽略此次点击"); + NSLog(@"[Combo effect] ⚠️ 点击间隔过短,忽略此次点击"); return; } #if RELEASE @@ -223,12 +232,13 @@ #endif [self.feedbackGenerator impactOccurred]; + NSLog(@"[Combo effect] 👆 连击面板被点击,发送礼物"); [[GiftComboManager sharedManager] sendGift]; [self.playImageView startAnimation]; [self.countdownRingView resetCountdown]; + NSLog(@"[Combo effect] ⏰ 重置连击倒计时"); // 处理点击事件 -// NSLog(@"有效点击处理"); // 延迟重置标志位 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 1521 连续震动 3 次 diff --git a/YuMi/Modules/YMRoom/View/SendGiftView/View/XPSendGiftView.m b/YuMi/Modules/YMRoom/View/SendGiftView/View/XPSendGiftView.m index 1525ad17..d935dd45 100644 --- a/YuMi/Modules/YMRoom/View/SendGiftView/View/XPSendGiftView.m +++ b/YuMi/Modules/YMRoom/View/SendGiftView/View/XPSendGiftView.m @@ -302,6 +302,7 @@ UIKIT_EXTERN NSString * const kFreeGiftCountdownNotification; } break; case ComboAction_Combo_Count_Update: { + NSLog(@"[Combo effect] 📱 收到连击计数更新回调"); [self.comboView updateCount]; } break; @@ -432,6 +433,18 @@ UIKIT_EXTERN NSString * const kFreeGiftCountdownNotification; NSMutableDictionary *data = [NSMutableDictionary dictionary]; [data addEntriesFromDictionary:dict]; + // 检查连击计数在云信消息中的传递 + NSNumber *comboCount = data[@"comboCount"]; + NSLog(@"[Combo effect] 📨 云信消息连击计数检查 - comboCount: %@, giftId: %ld", comboCount, (long)receiveModel.gift.giftId); + + // 如果连击计数为 0 或 nil,尝试修复 + if (!comboCount || [comboCount integerValue] < 1) { + NSLog(@"[Combo effect] 🚨 检测到云信消息中连击计数异常 - comboCount: %@", comboCount); + NSInteger currentCombo = [[GiftComboManager sharedManager] loadComboCount]; + NSLog(@"[Combo effect] 🔧 使用当前连击计数修复 - 当前: %ld", (long)currentCombo); + [data setObject:@(currentCombo) forKey:@"comboCount"]; + } + if (receiveModel.roomSendGiftType == RoomSendGiftType_AllMic) { // 全麦 if (receiveModel.gift.giftType == GiftType_Lucky) { // 如果是福袋 需要分开发送消息 [self sendLuckyBagGifts:receiveModel @@ -567,7 +580,9 @@ UIKIT_EXTERN NSString * const kFreeGiftCountdownNotification; NIMMessage *message = [[NIMMessage alloc]init]; NIMCustomObject *object = [[NIMCustomObject alloc] init]; - [attachment.data setObject:@([[GiftComboManager sharedManager] loadComboCountFromSendGiftView]) forKey:@"comboCount"]; + // 连击计数应该从 attachment.data 中获取,而不是重新计算 + // 这样可以避免重复递增连击计数 + NSLog(@"[Combo effect] 📨 发送云信消息 - 连击计数: %@", attachment.data[@"comboCount"]); attachment.data = [self removeNSNullValuesAndEmptyStringsRecursively:attachment.data]; @@ -703,7 +718,10 @@ UIKIT_EXTERN NSString * const kFreeGiftCountdownNotification; /// 初始化/重置 连击礼物功能状态 - (void)readyForCombo:(XPGiftCountModel *)giftCount gift:(GiftInfoModel *)giftInfo { + NSLog(@"[Combo effect] 🔧 准备连击状态 - giftType: %ld, segmentType: %ld", (long)giftInfo.giftType, (long)self.segmentType); + if (self.segmentType == GiftSegmentType_Pack) { + NSLog(@"[Combo effect] ❌ 背包礼物不支持连击"); [[GiftComboManager sharedManager] enableToCombo:NO]; return; } @@ -713,10 +731,12 @@ UIKIT_EXTERN NSString * const kFreeGiftCountdownNotification; giftInfo.giftType != GiftType_Lucky24 && giftInfo.giftType != GiftType_Lucky25 && giftInfo.giftType != GiftType_Bravo) { + NSLog(@"[Combo effect] ❌ 礼物类型不支持连击 - giftType: %ld", (long)giftInfo.giftType); [[GiftComboManager sharedManager] enableToCombo:NO]; return; } + NSLog(@"[Combo effect] ✅ 礼物支持连击,启用连击功能"); [[GiftComboManager sharedManager] enableToCombo:YES]; NSString *sessionID = self.usingplaceType == SendGiftType_User ? [NSString stringWithFormat:@"%ld", self.userArray.firstObject.uid] : [NSString stringWithFormat:@"%ld", [self.delegate getRoomInfo].roomId]; @@ -729,6 +749,8 @@ UIKIT_EXTERN NSString * const kFreeGiftCountdownNotification; [[GiftComboManager sharedManager] saveUserInfo:self.delegate.getUserInfo]; [[GiftComboManager sharedManager] saveSessionID:sessionID]; [[GiftComboManager sharedManager] saveGiftCountModel:giftCount]; + + NSLog(@"[Combo effect] ✅ 连击状态准备完成"); } #pragma mark - XPGiftBarViewDelegate @@ -738,8 +760,17 @@ UIKIT_EXTERN NSString * const kFreeGiftCountdownNotification; GiftInfoModel *giftInfo = self.giftInfoView.lastSelectGift; if (self.usingplaceType == SendGiftType_Room) { if (uids.count > 0) { + NSLog(@"[Combo effect] 🎁 开始送礼物流程"); [self readyForCombo:giftCount gift:giftInfo]; + [[GiftComboManager sharedManager] printComboState]; + + // 检查连击状态是否准备就绪 + if ([GiftComboManager sharedManager].enableCombo) { + NSLog(@"[Combo effect] ✅ 连击功能已启用,准备调用resetCombo"); + } else { + NSLog(@"[Combo effect] ❌ 连击功能未启用,无法进入连击状态"); + } ///送礼物的人 NSString * uidString = [self dealSendGiftUids:uids]; @@ -1156,16 +1187,25 @@ UIKIT_EXTERN NSString * const kFreeGiftCountdownNotification; // dispatch_after(delayTime, dispatch_get_main_queue(), ^{ // @kStrongify(self); if (self) { + NSLog(@"[Combo effect] 📱 检查连击状态 - enableCombo: %@", [GiftComboManager sharedManager].enableCombo ? @"YES" : @"NO"); + + // 检查 originDic 中的连击计数 + NSNumber *originComboCount = originDic[@"comboCount"]; + NSLog(@"[Combo effect] 📱 originDic 连击计数检查 - comboCount: %@", originComboCount); + if ([GiftComboManager sharedManager].enableCombo) { + NSLog(@"[Combo effect] 📱 启用连击模式,重置连击状态"); [[GiftComboManager sharedManager] resetCombo]; [self sendCustomMessage:receiveInfo oringinDic:originDic]; [self.comboView setupCurrentGold:receiveInfo.userPurse.diamonds.doubleValue]; @kWeakify(self); [[GiftComboManager sharedManager] setHandleComboSuccess:^(GiftReceiveInfoModel * _Nonnull receiveModel, NSMutableDictionary * _Nonnull originDic) { @kStrongify(self); + NSLog(@"[Combo effect] 📱 连击回调中发送消息 - comboCount: %@", originDic[@"comboCount"]); [self sendCustomMessage:receiveInfo oringinDic:originDic.copy]; }]; } else { + NSLog(@"[Combo effect] 📱 未启用连击模式,直接发送消息"); [self sendCustomMessage:receiveInfo oringinDic:originDic]; } } diff --git a/Banner手势优化实施总结.md b/docs/Banner手势优化实施总结.md similarity index 100% rename from Banner手势优化实施总结.md rename to docs/Banner手势优化实施总结.md diff --git a/Email-VerificationCode-Login-Flow.md b/docs/Email-VerificationCode-Login-Flow.md similarity index 100% rename from Email-VerificationCode-Login-Flow.md rename to docs/Email-VerificationCode-Login-Flow.md diff --git a/OAuth_Ticket_API_Documentation.md b/docs/OAuth_Ticket_API_Documentation.md similarity index 100% rename from OAuth_Ticket_API_Documentation.md rename to docs/OAuth_Ticket_API_Documentation.md diff --git a/PublicRoomMessageForward_Implementation.md b/docs/PublicRoomMessageForward_Implementation.md similarity index 99% rename from PublicRoomMessageForward_Implementation.md rename to docs/PublicRoomMessageForward_Implementation.md index 94e1b659..7669f1bb 100644 --- a/PublicRoomMessageForward_Implementation.md +++ b/docs/PublicRoomMessageForward_Implementation.md @@ -7,6 +7,7 @@ ## 实现方案 ### 1. 通知机制 + - 使用 NSNotificationCenter 进行消息转发 - 通知名称:`@"MessageFromPublicRoomWithAttachmentNotification"` - 通知对象:NIMMessage 对象 @@ -14,18 +15,22 @@ ### 2. 修改的文件 #### PublicRoomManager.m + - 在 `onRecvMessages:` 方法中添加转发逻辑 - 当检测到 `attachment.first == 106` 时发送通知 #### XPRoomViewController.m + - 在 `setupNotifications` 方法中注册通知监听 - 添加 `handlePublicRoomMessageForward:` 方法处理转发的消息 - 在 `dealloc` 中自动移除通知监听 #### YUMIConstant.m + - 添加常量定义:`kMessageFromPublicRoomWithAttachmentNotification`(已添加但当前使用字符串字面量) #### XPRoomViewController.h + - 添加常量声明(已添加但当前使用字符串字面量) ## 使用流程 @@ -82,5 +87,6 @@ if (attachment && attachment.first == 106) { ## 扩展性 如果将来需要转发其他类型的消息,可以: + 1. 修改条件判断(如 `attachment.first == 107`) 2. 或者使用更通用的通知名称,在通知数据中携带消息类型信息