Files
peko-ios/YuMi/Modules/YMRoom/View/SendGiftView/GiftComboManager.m

843 lines
30 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// GiftComboManager.m
// YuMi
//
// Created by P on 2024/9/5.
//
// 处理连击面板逻辑
#import "GiftComboManager.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <Bugly/Bugly.h>
#import "Api+Gift.h"
#import "UserInfoModel.h"
#import "AttachmentModel.h"
#import "XPGiftCountModel.h"
#import "GiftReceiveInfoModel.h"
#import "XPMessageRemoteExtModel.h"
#import "GiftComboFlagView.h"
// 通知常量实现
NSString * const kBoomStateForceResetNotification = @"BoomStateForceResetNotification";
@interface GiftComboManager ()
@property (nonatomic, assign) BOOL enableCombo;
@property (nonatomic, strong) NSMutableArray *requestQueue;
// 用来存储 GiftReceiveInfoModel 和 NSDictionary 的元数据队列
@property (nonatomic, strong) NSMutableArray *giftComboQueue;
@property (nonatomic, strong) NSMutableArray *comboFlagQueue;
@property (nonatomic, strong) dispatch_source_t comboFlagTimer;
@property (nonatomic, strong) UIView *containerView;
// 定时器,处理请求的调度器
@property (nonatomic, strong) dispatch_source_t timer;
@property (nonatomic, copy) NSArray *sendGiftToUIDs;
@property (nonatomic, assign) GiftSourceType giftSourceType;
@property (nonatomic, strong) GiftInfoModel *giftInfo;
@property (nonatomic, assign) RoomSendGiftType roomSendGiftType;
@property (nonatomic, copy) NSString *roomUID;
@property (nonatomic, copy) NSString *giftNumPerTimes;
@property (nonatomic, strong) UserInfoModel *sendGiftUserInfo;
@property (nonatomic, copy) NSString *sessionID;
@property (nonatomic, strong) XPGiftCountModel *countModel;
@property (nonatomic, assign) NSInteger combo;
@property (nonatomic, assign) bool isCombing;
@property (nonatomic, copy) void (^actionCallback)(ComboActionType type);
@property (nonatomic, copy) NSString *errorMessage;
@property (nonatomic, strong) NSMutableArray<GiftComboFlagView *> *activeViews; // 用于存储最多2个活跃的动画视图
@end
@implementation GiftComboManager
#pragma mark - 单例方法
- (void)dealloc {
[self stopProcessingGiftComboFlagQueue];
if (self.comboFlagQueue) {
self.comboFlagQueue = NULL;
}
}
+ (instancetype)sharedManager {
static GiftComboManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
sharedInstance.giftComboQueue = [NSMutableArray array];
sharedInstance.activeViews = [NSMutableArray array];
sharedInstance.comboFlagQueue = [NSMutableArray array];
sharedInstance.requestQueue = [NSMutableArray array];
[sharedInstance startProcessingGiftComboFlagQueue];
});
return sharedInstance;
}
//// 添加 GiftReceiveInfoModel 和 metadata 到队列
- (void)addGiftComboWithInfo:(GiftReceiveInfoModel *)info andMetadata:(NSDictionary *)metadata {
if (info && metadata) {
// 将元数据打包成字典并添加到队列
@synchronized (self) {
NSDictionary *comboData = @{@"info": info, @"metadata": metadata};
[self.giftComboQueue addObject:comboData];
}
// 启动定时器
[self startProcessingQueue];
}
}
- (void)addComboFromNIMAttachment:(AttachmentModel *)attachment {
if (attachment) {
// 将元数据打包成字典并添加到队列
@synchronized (self) {
[self.giftComboQueue addObject:attachment];
}
// 启动定时器
[self startProcessingQueue];
}
}
// 开始连击,重置
- (void)reset {
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);
// 发送通知,让 GiftComboView 重置显示
[[NSNotificationCenter defaultCenter] postNotificationName:@"ComboCountReset" object:nil];
// 检查是否应该显示连击面板
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 {
_combo = 1;
_errorMessage = @"";
self.actionCallback = action;
}
// 新增:实现其他简化接口方法
- (void)activate {
NSLog(@"[Combo effect] 🔧 激活连击功能");
self.enableCombo = YES;
}
- (void)deactivate {
NSLog(@"[Combo effect] 🔧 停用连击功能");
self.enableCombo = NO;
}
- (BOOL)isActive {
return self.isCombing && self.enableCombo;
}
- (NSInteger)currentCount {
// 确保连击计数最少为 1
if (self.combo < 1) {
NSLog(@"[Combo effect] ⚠️ currentCount: 连击计数异常重置为1 - 当前: %ld", (long)self.combo);
self.combo = 1;
}
return self.combo;
}
- (void)incrementCount {
NSLog(@"[Combo effect] 🔢 增加连击计数 - 当前: %ld -> %ld", (long)self.combo, (long)(self.combo + 1));
self.combo += 1;
}
- (void)clear {
NSLog(@"[Combo effect] 🗑️ 清除连击状态");
[self forceBoomStateReset];
// 通知UI移除连击面板
if (self.actionCallback) {
NSLog(@"[Combo effect] 📱 触发连击面板移除回调");
self.actionCallback(ComboAction_RemovePanel);
}
}
- (void)send {
NSLog(@"[Combo effect] 📤 发送连击礼物");
[self sendGift];
}
- (NSDictionary *)stateInfo {
return [self getComboStateInfo];
}
- (BOOL)canStartCombo {
return self.enableCombo && self.giftInfo != nil && self.sendGiftToUIDs.count > 0;
}
- (void)validateState {
[self validateAndFixComboCount];
}
- (void)handleError:(NSError *)error {
NSLog(@"[Combo effect] ❌ 处理错误: %@", error.localizedDescription);
self.errorMessage = error.localizedDescription;
}
- (NSString *)lastErrorMessage {
return self.errorMessage ?: @"";
}
- (void)clearError {
self.errorMessage = @"";
}
- (void)forceBoomStateReset {
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;
// 4. 重置combo计数为0
_combo = 0;
NSLog(@"[Combo effect] 🔄 combo计数重置为0");
// 注意:不重置 enableCombo保持连击功能可用状态
// self.enableCombo = NO; // 移除这行,保持连击功能可用
// 注意:不清理 actionCallback保持回调可用以便重新进入连击状态
// self.actionCallback = nil; // 移除这行,保持回调可用
// 5. 发送通知(优先级最高,通知所有相关组件)
NSLog(@"[Combo effect] 📢 发送强制重置通知");
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:kBoomStateForceResetNotification
object:nil];
});
// 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 ? @"可用" : @"为空");
}
// 无条件停止定时器
- (void)forceStopAllTimers {
if (self.timer) {
dispatch_source_cancel(self.timer);
self.timer = nil; // 立即置空,不等待回调
}
if (self.comboFlagTimer) {
dispatch_source_cancel(self.comboFlagTimer);
self.comboFlagTimer = nil;
}
}
// 清空所有队列
- (void)clearAllQueues {
@synchronized (self) {
[self.requestQueue removeAllObjects];
[self.giftComboQueue removeAllObjects];
[self.comboFlagQueue removeAllObjects];
}
}
- (NSInteger)loadTotalGiftNum {
return self.combo * self.countModel.giftNumber.integerValue * self.sendGiftToUIDs.count;
}
// 新增:检查连击状态是否有效
- (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];
}
- (void)removeComboFlag {
self.containerView = nil;
[self stopProcessingQueue];
[self stopProcessingGiftComboFlagQueue];
}
- (void)startProcessingGiftComboFlagQueue {
if (self.comboFlagTimer) {
return;
}
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_timer(timer,
DISPATCH_TIME_NOW,
0.2 * NSEC_PER_SEC,
0.01 * NSEC_PER_SEC);
@kWeakify(self);
dispatch_source_set_event_handler(timer, ^{
@kStrongify(self);
[self processGiftFlagQueue];
});
dispatch_resume(timer);
self.comboFlagTimer = timer;
}
- (void)stopProcessingGiftComboFlagQueue {
if (self.comboFlagTimer) {
dispatch_source_cancel(self.comboFlagTimer);
@kWeakify(self);
dispatch_source_set_cancel_handler(self.comboFlagTimer, ^{
@kStrongify(self);
self.comboFlagTimer = nil;
});
}
}
- (void)processGiftFlagQueue {
if (self.giftComboQueue.count == 0) {
return;
}
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];
});
}
- (void)handleGiftInfo:(GiftReceiveInfoModel *)receiveInfo {
if (receiveInfo.comboCount < 1) {
// 不正常的数据,不处理
return;
}
if ([self updateExistingViewWithModel:receiveInfo]) {
// 如果更新了现有视图,就不需要创建新视图
return;
}
if (self.activeViews.count >= 2) {
GiftComboFlagView *oldestView = [self.activeViews firstObject];
[self animateRemoveView:oldestView];
}
CGFloat positionY = kGetScaleWidth(380);
CGFloat positionX = isMSRTL() ? -self.containerView.bounds.size.width : self.containerView.bounds.size.width;
GiftComboFlagView *flagView = [[GiftComboFlagView alloc] initWithFrame:CGRectMake(positionX,
positionY,
kGetScaleWidth(300),
50)];
@kWeakify(self);
@kWeakify(flagView);
[flagView setTimerEnd:^{
@kStrongify(self);
@kStrongify(flagView);
[self animateRemoveView:flagView];
}];
[flagView updateReceiveInfoModel:receiveInfo animationType:0];
[self allCurrentFlagMoveDown];
[self.containerView addSubview:flagView];
[self.activeViews insertObject:flagView atIndex:0];
[self animateView:flagView positionY:positionY];
}
- (void)allCurrentFlagMoveDown {
CGFloat positionY = kGetScaleWidth(380);
[self.activeViews enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(GiftComboFlagView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
dispatch_async(dispatch_get_main_queue(), ^{
CGRect rect = obj.frame;
rect.origin.y = positionY + idx * 50;
obj.frame = rect;
});
}];
}
- (void)animateView:(GiftComboFlagView *)flagView positionY:(CGFloat)positionY {
[UIView animateWithDuration:0.1
animations:^{
if (isMSRTL()) {
// 获取屏幕宽度
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
// 计算新的 x 坐标:屏幕宽度 - 视图宽度 - 右边距
CGFloat newX = screenWidth - 20 - kGetScaleWidth(300);
// 更新 flagView 的 frame使右边距离屏幕右边 20 像素
flagView.frame = CGRectMake(newX, positionY, kGetScaleWidth(300), 50);
} else {
flagView.frame = CGRectMake(20, positionY, kGetScaleWidth(300), 50);
}
} completion:^(BOOL finished) {
[self allCurrentFlagMoveDown];
}];
}
- (void)animateRemoveView:(GiftComboFlagView *)flagView {
[flagView removeFromSuperview];
if ([self.activeViews containsObject:flagView]) {
[self.activeViews removeObject:flagView];
flagView = nil;
}
[self allCurrentFlagMoveDown];
}
// 更新现有 View 的数据,如果存在相同的 ID
- (BOOL)updateExistingViewWithModel:(GiftReceiveInfoModel *)model {
NSInteger index = 0;
for (GiftComboFlagView *existingFlag in self.activeViews) {
if (existingFlag.superview == nil) {
continue;
}
if ([existingFlag.receiveInfo isEqual:model]) {
[self updateComboFlag:existingFlag with:model];
return YES;
}
index++;
}
return NO;
}
- (void)updateComboFlag:(GiftComboFlagView *)flagView with:(GiftReceiveInfoModel *)model {
[flagView updateReceiveInfoModel:model animationType:1];
}
// MARK: Logic is 连击面板出现后,每点击一次,就触发一次面板最后的请求,请求成功后,构造云信消息体,消息体进入队列并按 0.25s 一次的频率发送消息
#pragma mark - 管理队列
// 开始处理队列
- (void)startProcessingQueue {
if (self.timer) {
return; // 如果定时器已经在运行,直接返回
}
// 创建 GCD 定时器
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
//#if DEBUG
// dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC, 0.01 * NSEC_PER_SEC);
//#else
// 设置定时器时间间隔:每 0.25 秒执行一次
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 0.25 * NSEC_PER_SEC, 0.01 * NSEC_PER_SEC);
//#endif
// 定时器触发的事件处理
dispatch_source_set_event_handler(self.timer, ^{
[self processRequestQueue];
[self processGiftComboQueue];
});
// **立即执行一次处理方法**
[self processRequestQueue];
[self processGiftComboQueue];
// 启动定时器
dispatch_resume(self.timer);
}
// 停止处理队列
- (void)stopProcessingQueue {
if (self.timer) {
if (self.requestQueue.count == 0 && self.giftComboQueue.count == 0) {
// 取消定时器
dispatch_source_cancel(self.timer);
// 设置取消回调,在资源完全释放后将 timer 置为 nil
@kWeakify(self);
dispatch_source_set_cancel_handler(self.timer, ^{
@kStrongify(self);
self.timer = nil;
});
}
}
}
// 处理队列中的第一个请求
- (void)processGiftComboQueue {
@synchronized (self) {
if (self.giftComboQueue.count > 0) {
// 获取并移除队列中的第一个元数据
AttachmentModel *attachment = [self.giftComboQueue firstObject];
[self.giftComboQueue xpSafeRemoveObjectAtIndex:0];
// 处理逻辑
[self processGiftComboWith:attachment];
} else {
[self stopProcessingQueue];
}
}
}
// 处理元数据的实际逻辑
- (void)processGiftComboWith:(AttachmentModel *)info {
[self sendCustomMessage:info];
}
- (NSString *)loadErrorMessage {
return self.errorMessage;
}
- (void)processRequestQueue {
@synchronized (self) {
if (self.requestQueue.count > 0) {
// 获取并移除队列中的第一个元数据
NSDictionary *dic = [self.requestQueue xpSafeObjectAtIndex:0];
if (dic) {
[self handleSendGift:dic];
[self.requestQueue removeObject:dic];
}
} else {
[self stopProcessingQueue];
}
}
}
#pragma mark - Gift meta data
// 统一配置方法替代多个save方法
- (void)configureWithGiftInfo:(GiftInfoModel *)giftInfo
targetUIDs:(NSArray *)UIDs
roomUID:(NSString *)roomUID
sessionID:(NSString *)sessionID
userInfo:(UserInfoModel *)userInfo
countModel:(XPGiftCountModel *)countModel
sourceType:(GiftSourceType)sourceType
sendType:(RoomSendGiftType)sendType
giftNum:(NSString *)giftNum {
NSLog(@"[Combo effect] 🔧 统一配置连击参数");
self.giftInfo = giftInfo;
self.sendGiftToUIDs = UIDs;
self.roomUID = roomUID;
self.sessionID = sessionID;
self.sendGiftUserInfo = userInfo;
self.countModel = countModel;
self.giftSourceType = sourceType;
self.roomSendGiftType = sendType;
self.giftNumPerTimes = giftNum;
NSLog(@"[Combo effect] ✅ 连击参数配置完成 - giftId: %ld, targetCount: %ld",
(long)giftInfo.giftId, (long)UIDs.count);
}
- (BOOL)loadEnable {
return self.enableCombo;
}
#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) {
allUIDs = [allUIDs stringByAppendingString:@","];
}
allUIDs = [allUIDs stringByAppendingString:item];
}
NSDictionary *dic = @{
@"targetUids":allUIDs,
@"giftNum":self.giftNumPerTimes,
@"sendType":[NSString stringWithFormat:@"%ld", GiftSendType_OnMic],
@"giftId":[NSString stringWithFormat:@"%ld", self.giftInfo.giftId],
@"giftSource":[NSString stringWithFormat:@"%ld", self.giftSourceType],
@"giftType":[NSString stringWithFormat:@"%ld", self.roomSendGiftType],
@"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];
NSArray *array = [allUIDs componentsSeparatedByString:@","];
receive.receiveGiftNumberUser = array.count;
[self handleSendGiftSuccess:receive sourceData:data];
[[NSNotificationCenter defaultCenter] postNotificationName:@"receiveLuckGiftWinning"
object:@{@"CurrentGold": receive.userPurse.diamonds,
@"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:@"服务器繁忙,请稍后重试 - %@", msg];
#else
self.errorMessage = @"Over Heat & try later";
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSMutableDictionary *logDic = [@{@"targetUids": allUIDs,
@"giftNum": self.giftNumPerTimes} mutableCopy];
[logDic addEntriesFromDictionary:dic];
[logDic setObject:[NSThread callStackSymbols] forKey:@"call stack symbols"];
[logDic setObject:msg forKey:@"error message"];
[logDic setObject:@"gift/sendV5" forKey:@"http method"];
[Bugly reportError:[NSError errorWithDomain:[NSString stringWithFormat:@"UID: %@,API: %@ 异常",
[AccountInfoStorage instance].getUid,
@"gift/sendV5"]
code:code
userInfo:logDic]];
});
#endif
// 临时错误,不重置连击状态,允许用户重试
} else if (code == 31005) {
// 余额不足,需要重置连击状态
NSLog(@"[Combo effect] 💰 余额不足,强制移除连击状态");
self.errorMessage = YMLocalizedString(@"XPCandyTreeInsufficientBalanceView1");
[self clear];
} else if (code == 8535) {
// VIP等级不足需要重置连击状态, 但不可能出现
NSLog(@"[Combo effect] 👑 VIP等级不足强制移除连击状态");
self.errorMessage = @"";
[self clear];
} 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 clear];
}
}
if (self.actionCallback) {
self.actionCallback(ComboAction_Error);
}
}
}
targetUids:allUIDs
giftNum:self.giftNumPerTimes
sendType:[dic objectForKey:@"sendType"]
giftId:[dic objectForKey:@"giftId"]
giftSource:[dic objectForKey:@"giftSource"]
giftType:[dic objectForKey:@"giftType"]
roomUid:[dic objectForKey:@"roomUid"]
msg:@""
uid:[AccountInfoStorage instance].getUid];
}
- (void)handleSendGiftSuccess:(GiftReceiveInfoModel *)receive
sourceData:(BaseModel *)response {
NSLog(@"[Combo effect] 🎉 连击礼物发送成功 - 当前combo: %ld", (long)self.combo);
// 验证连击计数有效性
[self validateAndFixComboCount];
// 在API成功时递增combo计数
if (self.isCombing) {
NSLog(@"[Combo effect] 🔢 API成功递增连击计数 - 当前: %ld -> %ld", (long)self.combo, (long)(self.combo + 1));
self.combo += 1;
// 更新UI显示
if (self.actionCallback) {
self.actionCallback(ComboAction_Combo_Count_Update);
}
}
NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:response.data];
// 确保连击计数最少为 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;
message.messageObject = object;
UserInfoModel *userInfo = self.sendGiftUserInfo;
XPMessageRemoteExtModel *extModel = [[XPMessageRemoteExtModel alloc] init];
extModel.androidBubbleUrl = userInfo.androidBubbleUrl;
extModel.iosBubbleUrl = userInfo.iosBubbleUrl;
extModel.fromSayHelloChannel = userInfo.fromSayHelloChannel;
extModel.platformRole = userInfo.platformRole;
NSMutableDictionary *remoteExt = [NSMutableDictionary dictionaryWithObject:extModel.model2dictionary forKey:[NSString stringWithFormat:@"%ld", userInfo.uid]];
message.remoteExt = remoteExt;
//构造会话
NIMSession *session = [NIMSession session:self.sessionID type:NIMSessionTypeChatroom];
NSError *error = nil;
[[NIMSDK sharedSDK].chatManager sendMessage:message toSession:session error:&error];
if (error) {
NSLog(@"[Combo effect] ❌ 云信消息发送失败 - error: %@", error.localizedDescription);
} else {
NSLog(@"[Combo effect] ✅ 云信消息发送成功");
}
}
@end