Files
peko-ios/YuMi/Modules/YMRoom/View/AnimationView/RoomAnimationView.m

3516 lines
139 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.

//
// RoomAnimationView.m
// YuMi
//
// Created by P on 2025/1/13.
//
//banner 手势处理会有遮挡其他视图操作的问题
#import "RoomAnimationView.h"
#import <POP.h>
#import <SVGA.h>
#import <libpag/libpag.h>
#import <NIMSDK/NIMSDK.h>
#import <UIImageView+WebCache.h>
#import "UIView+VAP.h"
#import "ClientConfig.h"
#import "XPGiftStorage.h"
#import "UserInfoModel.h"
#import "RoomInfoModel.h"
#import "MicroQueueModel.h"
#import "AttachmentModel.h"
#import "QGVAPConfigModel.h"
#import "ActivityInfoModel.h"
#import "GiftReceiveInfoModel.h"
#import "XPRoomEnterHideTipView.h"
#import "XPMessageRemoteExtModel.h"
#import "PIBaseAnimationViewModel.h"
#import "XPRoomGiftAnimationParser.h"
#import "GiftComboManager.h"
#import "GiftAnimationManager.h"
#import "MSRoomGameWebVC.h"
#import "XPRoomViewController.h"
#import "PIUniversalBannerView.h"
#import "PIUniversalBannerModel.h"
#import "CPGiftBanner.h"
#import "CPLevelUpAnimation.h"
#import "CPBindingAnimation.h"
#import "GameUniversalBannerView.h"
#import "LuckyGiftWinningFlagView.h"
#import "LuckyGiftWinningBannerView.h"
#import "RoomHighValueGiftBannerAnimation.h"
#import "LuckyPackageBannerView.h"
#import "BravoGiftBannerView.h"
#import "XCCurrentVCStackManager.h"
#import "BravoGiftWinningFlagView.h"
#import "RoomEnterModel.h"
// Old Methods
#import "DatingInfoModel.h"
#import "XPWebViewController.h"
#import "XPRoomCandyGiftView.h"
#import "XPSailingAnimationView.h"
#import "AcrossRoomPKPrizeModel.h"
#import "XPRoomNobleLevelUpView.h"
#import "XPRoomGiftCompoundView.h"
#import "XPRoomGiftBroadcastView.h"
#import "XPRoomLuckyBigPrizeView.h"
#import "XPTreasureFairyGiftView.h"
#import "XPAcrossRoomPKPrizeView.h"
#import "PIRoomGiftBroadcastWindow.h"
#import "XPRoomDatingAnimationView.h"
#import "XPRoomAnchorRankBannerView.h"
#import "XPRoomGraffitiGiftAnimationView.h"
#import "XPRoomFunctionContainerView.h"
#import "XPRoomRankEntranceView.h"
#import "XPRoomAnchorRankEnterView.h"
#import "MSRoomOnLineView.h"
static const CGFloat kTipViewStayDuration = 3.0;
static const CGFloat kTipViewMoveDuration = 0.5;
@interface RoomAnimationView () <
PAGViewListener,
SVGAPlayerDelegate,
HWDMP4PlayDelegate,
GiftAnimationDelegate,
NIMBroadcastManagerDelegate,
PIUniversalBannerViewDelegate,
XPRoomGiftBroadcastViewDelegate,
XPRoomLuckyBigPrizeViewDelegate,
PIRoomGiftBroadcastWindowDelegate,
XPRoomAnchorRankBannerViewDelegate,
XPRoomGraffitiGiftAnimationViewDelegate,
UIGestureRecognizerDelegate
>
@property (nonatomic, weak) id<RoomHostDelegate>hostDelegate;
///最底层
@property (nonatomic, strong) XPRoomAnimationHitView *bottomContainer;
///中层
@property (nonatomic, strong) XPRoomAnimationHitView *middleContainer;
///顶层
@property (nonatomic, strong) XPRoomAnimationHitView *topContainer;
@property (nonatomic, strong) XPRoomAnimationHitView *bannerContainer;
@property (nonatomic, strong) UIView *bannerSwipeGestureContainer;
@property (nonatomic, strong) UIView *bannerLeftTapGestureContainer;
@property (nonatomic, strong) UIView *bannerRightTapGestureContainer;
/// --- 进场
/// 存放进房待播放动画的"队列"(这里用数组模拟队列 FIFO
@property (nonatomic, strong) NSMutableArray<NSDictionary *> *enterRoomAnimationQueue;
/// 标记当前是否有进房动画在执行
@property (nonatomic, assign) BOOL isEnterRoomAnimating;
@property (nonatomic, strong) SVGAImageView *enterEffectView;
/// --- 礼物
@property(nonatomic, strong) PAGView *pagGiftEffectView;
@property(nonatomic, strong) SVGAParser *vggParser;
@property(nonatomic, assign) BOOL isPlayingGiftEffect;
@property(nonatomic, strong) NSMutableArray *svgaQueue;
@property(nonatomic, strong) VAPView *vapGiftEffectView;
@property(nonatomic, strong) SVGAImageView *vggGiftEffectView;
@property(nonatomic, strong) NSMutableArray *mp4AvatarLoaders;
@property(nonatomic, copy) NSString *GiftDynamicEffectListPath;
@property(nonatomic, strong) dispatch_source_t giftEffectTimer;
@property(nonatomic, strong) dispatch_queue_t giftEffectsQueue;
@property(nonatomic, strong) XPRoomGiftAnimationParser *vapParser;
@property(nonatomic, strong) GiftAnimationManager *giftAnimationManager;
@property(nonatomic, strong) GiftReceiveInfoModel *mp4TempReceiveInfoModel;
/// --- 飘屏
@property (nonatomic, strong) NSMutableArray *roomBannertModelsQueueV2; // 特效播放队列,包括幸运礼物 banner CP banner 和 CP 特效
@property (nonatomic, assign) BOOL isRoomBannerV2Displaying;
// --- Brove 金币动画
@property (nonatomic, strong) SVGAVideoEntity *broveSVGAEntity_lv_1;
@property (nonatomic, strong) SVGAVideoEntity *broveSVGAEntity_lv_2;
@property (nonatomic, strong) SVGAVideoEntity *broveSVGAEntity_lv_3;
@property (nonatomic, strong) NSMutableArray *broveSVGAQueue;
@property (nonatomic, assign) BOOL isBroveSVGAPlaying;
@property (nonatomic, assign) NSInteger viewIndex;
/// --- 座驾
///座驾pag动效
@property(nonatomic, strong) PAGView *carPagEffectView;
///座驾VAP特效
@property(nonatomic, strong) VAPView *carVapEffectView;
@property(nonatomic, strong) SVGAImageView *carSVGAEffectView;
@property(nonatomic, strong) NSMutableArray<NSDictionary *> *carEffectQueue;
/// --- 旧逻辑,有需要再重构
@property(nonatomic, assign) BOOL isPlayOfB;
@property(nonatomic, strong) NSMutableArray<PIBaseAnimationViewModel *> *animationListB; // 玩法
@property(nonatomic, assign) CGFloat broadCastHieght;
@property (nonatomic, strong) NetImageView *imageLoader;
@property (nonatomic, strong) SVGAImageView *datingEffectView;
@property (nonatomic, strong) NSMutableArray<AttachmentModel *> *sailingQueue;
@property (nonatomic, strong) NSMutableArray<DatingInfoModel *> *datingEffectQueue;
@property (nonatomic, strong) NSMutableArray<AttachmentModel *> *graffitiGiftQueue;
@property (nonatomic, strong) NSMutableArray<AcrossRoomPKPrizeModel *> *acrossRoomPKQueue;
@property (nonatomic,strong) SVGAImageView *luckyGiftEffectView; ///福袋礼物送礼物的特效
@property (nonatomic, strong) VAPView *luckyVapGiftEffectView; ///福袋礼物VAP特效
@property(nonatomic, strong) NSMutableArray <PIUniversalBannerView *>* universalBannerViewCaches;
// Banner 手势相关属性
@property(nonatomic, assign) CGPoint savedTapPoint;
@property(nonatomic, assign) BOOL hasSavedTapPoint;
@end
@implementation RoomAnimationView
- (void)setIsPlayOfB:(BOOL)isPlayOfB {
_isPlayOfB = isPlayOfB;
}
- (void)dealloc
{
[[NIMSDK sharedSDK].broadcastManager removeDelegate:self];
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[self pop_removeAllAnimations];
if (_giftEffectTimer && !dispatch_source_testcancel(_giftEffectTimer)) {
dispatch_source_cancel(_giftEffectTimer);
_giftEffectTimer = nil;
}
if (_giftEffectsQueue) {
self.giftEffectsQueue = NULL;
}
}
-(void)resumeTimer{
if(self.giftEffectTimer != nil){
dispatch_source_cancel(self.giftEffectTimer);
self.giftEffectTimer = nil;
}
[self.pagGiftEffectView removeListener:self];
self.hostDelegate = nil;
[[GiftComboManager sharedManager] removeComboFlag];
}
- (instancetype)initWithHostDelegate:(id<RoomHostDelegate>)hDelegate {
if (self = [super init]) {
self.hostDelegate = hDelegate;
[[NIMSDK sharedSDK].broadcastManager addDelegate:self];
// 确保RoomAnimationView可以接收用户交互
self.userInteractionEnabled = YES;
[self setup];
}
return self;
}
#pragma mark - SETUP
- (void)setup {
[self setupUI];
[self setupEnterRoom];
[self setupGiftEffects];
[self setupBanner];
[self setupCar];
[self setupOldMethods];
[self addBnnerContainGesture];
}
- (void)setupUI {
[self addSubview:self.bottomContainer];
[self insertSubview:self.middleContainer aboveSubview:self.bottomContainer];
[self insertSubview:self.topContainer aboveSubview:self.middleContainer];
[self insertSubview:self.bannerContainer aboveSubview:self.topContainer];
[self.bottomContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self);
}];
[self.middleContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self);
}];
[self.topContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(self);
}];
[self.bannerContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(self).offset(kNavigationHeight);
make.leading.trailing.mas_equalTo(self);
make.height.mas_equalTo(80);
}];
}
- (void)setupEnterRoom {
self.enterRoomAnimationQueue = [NSMutableArray array];
}
- (void)setupGiftEffects {
self.GiftDynamicEffectListPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) xpSafeObjectAtIndex:0] stringByAppendingPathComponent:@"GiftDynamicEffectList"];
self.giftAnimationManager = [[GiftAnimationManager alloc] initWithContainerView:self.bottomContainer];
self.giftAnimationManager.delegate = self;
_giftEffectsQueue = dispatch_queue_create("com.RoomGiftEffects.queue", DISPATCH_QUEUE_SERIAL);
}
- (void)setupBanner {
_roomBannertModelsQueueV2 = [NSMutableArray array];
}
#pragma mark - Legacy Support
- (void)setupCar {
_carEffectQueue = [NSMutableArray array];
}
- (void)setupOldMethods {
_broadCastHieght = 190 - 150 + kGetScaleWidth(69);
_sailingQueue = @[].mutableCopy;
_datingEffectQueue = @[].mutableCopy;
_graffitiGiftQueue = @[].mutableCopy;
_acrossRoomPKQueue = @[].mutableCopy;
_animationListB = @[].mutableCopy;
}
#pragma mark - Method: Enter Roooooom
- (void)enterRoom:(NIMMessage *)message content:(NIMChatroomNotificationContent *)content {
NIMMessageChatroomExtension *messageExt = (NIMMessageChatroomExtension *)message.messageExt;
NSDictionary * dic = [(NSDictionary *)messageExt.roomExt.toJSONObject objectForKey:message.from];
XPMessageRemoteExtModel *extModel = [XPMessageRemoteExtModel modelWithJSON:dic];
if (extModel.platformRole == 1) {
return;
}
if (extModel.enterHide) {
//隐身进房
if ([message.from isEqualToString:[AccountInfoStorage instance].getUid]) {
[self createEnterHideAnimation];
}
} else {
[self userEnterRoom:content ext:extModel];
}
}
///自己的隐身进房提示
- (void)createEnterHideAnimation {
NSDictionary * dic= @{@"title":@"隐身进房",
@"isMe":@"",
@"experLevelSeq":@"",
@"effectPath" : @""};
[self.enterRoomAnimationQueue addObject:dic];
[self tryDequeueAnimation];
}
- (void)userEnterRoom:(NIMChatroomNotificationContent *)content ext:(XPMessageRemoteExtModel *)extModel {
NSString *userName = [self _resolveUserNameFromContent:content extModel:extModel];
NSString *title = [NSString stringWithFormat:YMLocalizedString(@"XPRoomAnimationView0"), userName];
NSDictionary * dic= @{@"title":title,
@"experLevelSeq":[NSString stringWithFormat:@"%ld", extModel.experLevelSeq],
@"effectPath" : extModel.enterRoomEffects.length ? extModel.enterRoomEffects : @""};
[self.enterRoomAnimationQueue addObject:dic];
[self tryDequeueAnimation];
}
- (void)tryDequeueAnimation {
// 如果当前正有动画在播放或者队列里啥都没有直接return
if (self.isEnterRoomAnimating || self.enterRoomAnimationQueue.count == 0) {
return;
}
self.isEnterRoomAnimating = YES;
// 取出队列头部的动画信息并移除
NSDictionary *dic = [self.enterRoomAnimationQueue firstObject];
if (self.enterRoomAnimationQueue.count > 0) {
[self.enterRoomAnimationQueue xpSafeRemoveObjectAtIndex:0];
}
NSString *title = [dic objectForKey:@"title"];
if ([title isEqualToString:@"隐身进房"]) {
[self playHideEnterRoomAnimation];
} else {
// 开始执行动画
[self playUserEnterRoomAnimation:[dic objectForKey:@"title"]
experLevelSeq:[dic objectForKey:@"experLevelSeq"]
effectPath:[dic objectForKey:@"effectPath"]
isCPEnter:[[dic objectForKey:@"isCP"] boolValue]];
}
}
- (void)playHideEnterRoomAnimation {
XPRoomEnterHideTipView *enterHideTipView = [[XPRoomEnterHideTipView alloc] initWithFrame:CGRectMake(KScreenWidth,
(KScreenHeight - 48) * 0.5,
KScreenWidth,
48)];
[self.bottomContainer addSubview:enterHideTipView];
@kWeakify(self);
[self enterRoomAnimationFor:enterHideTipView
startFrom:enterHideTipView.center
startTo:CGPointMake(enterHideTipView.frame.size.width / 2, enterHideTipView.center.y)
endFrom:CGPointMake(0, enterHideTipView.center.y)
endTo:CGPointMake(-KScreenWidth / 2, enterHideTipView.center.y)
duration:CACurrentMediaTime() + kTipViewStayDuration
completion:^(BOOL finished) {
@kStrongify(self);
[self endAnimationEnterEffect];
}];
}
- (void)playUserEnterRoomAnimation:(NSString *)title
experLevelSeq:(NSString *)experLevelSeq
effectPath:(NSString *)effectPath
isCPEnter:(BOOL)isCP {
NSDictionary *attributes = @{
NSFontAttributeName:kFontRegular(26),
NSForegroundColorAttributeName:[UIColor whiteColor]
};
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:title
attributes:attributes];
[attributeString setYy_alignment:NSTextAlignmentLeft];
BOOL hasEffectPath = ![NSString isEmpty:effectPath];
[self addEnterEffectView: hasEffectPath];
if (isCP) {
[self playCPPPPEnterRoomSvgaWith:attributeString];
} else if (hasEffectPath) {
[self playEnterRoomSvga:effectPath
content:attributeString
needMoveAnimation:YES];
} else {
[self playEnterRoomSvgaWith:experLevelSeq
content:attributeString];
}
}
- (void)addEnterEffectView:(BOOL)hasEffectPath {
if (self.enterEffectView.superview == nil) {
[self.bottomContainer addSubview:self.enterEffectView];
}
self.enterEffectView.loops = hasEffectPath ? 0 : 1;
self.enterEffectView.frame = CGRectMake(hasEffectPath ? KScreenWidth : 0,
340 + kSafeAreaTopHeight,
KScreenWidth,
hasEffectPath ? 75 : 50);
}
- (void)playEnterRoomSvga:(NSString *)path
content:(NSAttributedString *)content
needMoveAnimation:(BOOL)isNeed {
@kWeakify(self);
SVGAParser *parser = [[SVGAParser alloc] init];
[parser parseWithURL:[NSURL URLWithString:path]
completionBlock:^(SVGAVideoEntity * _Nullable videoItem) {
@kStrongify(self);
self.enterEffectView.alpha = 1;
self.enterEffectView.hidden = NO;
self.enterEffectView.videoItem = videoItem;
[self.enterEffectView setAttributedText:content forKey:@"room_text"];
[self.enterEffectView startAnimation];
if (isNeed) {
[self popAnimationEnterEffect];
}
} failureBlock:^(NSError * _Nullable error) {
@kStrongify(self);
[self endAnimationEnterEffect];
}];
}
- (void)playEnterRoomSvgaWith:(NSString *)seq
content:(NSAttributedString *)content {
NSInteger seqNum = [NSString isEmpty:seq] ? 0 : [seq integerValue];
NSString *path = [self _mapExperLevelSeqToLocalKey:seqNum];
if ([NSString isEmpty:path]) {
[self endAnimationEnterEffect];
return;
}
NSString *targetPath = [NSString stringWithFormat:@"%@/%@.svga", @"https://image.molistar.xyz", path];
[self playEnterRoomSvga:targetPath content:content needMoveAnimation:NO];
}
- (void)playCPPPPEnterRoomSvgaWith:(NSAttributedString *)content {
if ([NSString isEmpty:content.string]) {
[self endAnimationEnterEffect];
return;
}
NSString *path = @"CP进场";
@kWeakify(self);
SVGAParser *parser = [[SVGAParser alloc] init];
[parser parseWithNamed:path inBundle:[NSBundle mainBundle] completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
@kStrongify(self);
self.enterEffectView.loops = 0;
self.enterEffectView.alpha = 1;
self.enterEffectView.hidden = NO;
self.enterEffectView.videoItem = videoItem;
[self.enterEffectView setAttributedText:content forKey:@"room_text"];
[self.enterEffectView startAnimation];
[self popAnimationEnterEffect];
} failureBlock:^(NSError * _Nonnull error) {
@kStrongify(self);
[self endAnimationEnterEffect];
}];
}
- (void)popAnimationEnterEffect {
@kWeakify(self);
[self enterRoomAnimationFor:self.enterEffectView
startFrom:self.enterEffectView.center
startTo:CGPointMake(self.enterEffectView.frame.size.width / 2, self.enterEffectView.center.y)
endFrom:CGPointMake(0, self.enterEffectView.center.y)
endTo:CGPointMake(-KScreenWidth / 2, self.enterEffectView.center.y)
duration:CACurrentMediaTime() + kTipViewStayDuration
completion:^(BOOL finished) {
@kStrongify(self);
[self endAnimationEnterEffect];
}];
}
- (void)endAnimationEnterEffect {
self.isEnterRoomAnimating = NO;
[self.enterEffectView stopAnimation];
self.enterEffectView.hidden = YES;
[self.enterEffectView removeFromSuperview];
[self tryDequeueAnimation];
}
#pragma mark - Method: Banner
- (void)inserBannerModelToQueue:(AttachmentModel *)obj {
// 参数验证
if (!obj || ![obj isKindOfClass:[AttachmentModel class]]) {
NSLog(@"⚠️ 警告: inserBannerModelToQueue 接收到无效参数: %@", obj);
return;
}
#if DEBUG
// DEBUG环境复制banner数据用于测试
BOOL enableBannerCopy = obj.second == Custom_Message_Sub_Super_Gift_Banner;// YES; // 设置为NO可以禁用复制功能
NSInteger copyCount = 10; // 可以调整这个数字来改变复制数量
if (enableBannerCopy) {
NSLog(@"🧪 DEBUG环境收到banner数据复制%ld份用于测试", (long)copyCount);
NSLog(@"🧪 原始banner类型: %@", NSStringFromClass([obj class]));
// 添加原始数据
[self.roomBannertModelsQueueV2 addObject:obj];
// 复制指定份数
for (int i = 1; i < copyCount; i++) {
AttachmentModel *copiedObj = [[AttachmentModel alloc] init];
// 安全复制data
if ([obj.data respondsToSelector:@selector(mutableCopy)]) {
copiedObj.data = [obj.data mutableCopy];
} else if ([obj.data respondsToSelector:@selector(copy)]) {
copiedObj.data = [obj.data copy];
} else {
copiedObj.data = obj.data; // 直接引用,注意这可能不是深拷贝
}
copiedObj.first = obj.first;
copiedObj.second = obj.second;
copiedObj.isBroadcast = obj.isBroadcast;
copiedObj.seq = obj.seq;
NSLog(@"🧪 复制第%d份banner数据", i + 1);
[self.roomBannertModelsQueueV2 addObject:copiedObj];
}
NSLog(@"🧪 队列中banner总数: %ld", (long)self.roomBannertModelsQueueV2.count);
// 显示队列中banner类型的分布
NSMutableDictionary *typeCount = [NSMutableDictionary dictionary];
for (AttachmentModel *banner in self.roomBannertModelsQueueV2) {
NSString *typeKey = [NSString stringWithFormat:@"%d", banner.second];
NSNumber *count = typeCount[typeKey];
typeCount[typeKey] = @(count.integerValue + 1);
}
NSLog(@"🧪 队列中banner类型分布:");
for (NSString *typeKey in typeCount.allKeys) {
NSLog(@" - 类型%@: %@个", typeKey, typeCount[typeKey]);
}
} else {
// 禁用复制功能,正常添加
NSLog(@"🧪 DEBUG环境复制功能已禁用正常添加banner");
[self.roomBannertModelsQueueV2 addObject:obj];
}
#else
// 生产环境:正常添加
[self.roomBannertModelsQueueV2 addObject:obj];
#endif
if (!self.isRoomBannerV2Displaying) {
[self processNextRoomEffectAttachment];
}
}
- (void)sortBannerQueue {
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
NSString *currentRoomUid = @(roomInfo.uid).stringValue;
NSString *currentUid = [AccountInfoStorage instance].getUid;
[self.roomBannertModelsQueueV2 sortUsingComparator:^NSComparisonResult(AttachmentModel * _Nonnull obj1, AttachmentModel * _Nonnull obj2) {
// 检查 obj1 的属性
NSArray *obj1UidList = [obj1.data valueForKey:@"uidList"];
NSNumber *obj1RoomUid = [obj1.data valueForKey:@"roomUid"];
BOOL obj1IsCurrentUser = obj1UidList && [obj1UidList containsObject:currentUid];
BOOL obj1IsCurrentRoom = obj1RoomUid && [obj1RoomUid.stringValue isEqualToString:currentRoomUid];
// 检查 obj2 的属性
NSArray *obj2UidList = [obj2.data valueForKey:@"uidList"];
NSNumber *obj2RoomUid = [obj2.data valueForKey:@"roomUid"];
BOOL obj2IsCurrentUser = obj2UidList && [obj2UidList containsObject:currentUid];
BOOL obj2IsCurrentRoom = obj2RoomUid && [obj2RoomUid.stringValue isEqualToString:currentRoomUid];
if (obj1IsCurrentUser && !obj2IsCurrentUser) {
return NSOrderedAscending;
} else if (!obj1IsCurrentUser && obj2IsCurrentUser) {
return NSOrderedDescending;
} else if (obj1IsCurrentRoom && !obj2IsCurrentRoom) {
return NSOrderedAscending;
} else if (!obj1IsCurrentRoom && obj2IsCurrentRoom) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
}
- (void)processNextRoomEffectAttachment {
NSLog(@"🔄 processNextRoomEffectAttachment 被调用 - 当前状态: isRoomBannerV2Displaying=%@, 队列数量: %ld",
self.isRoomBannerV2Displaying ? @"YES" : @"NO", (long)self.roomBannertModelsQueueV2.count);
// 检查队列是否有元素
if (self.roomBannertModelsQueueV2.count == 0) {
// 如果队列为空,停止处理
self.isRoomBannerV2Displaying = NO;
NSLog(@"🔄 队列为空,停止处理");
return;
}
if (self.isRoomBannerV2Displaying) {
NSLog(@"🔄 已有banner正在显示跳过处理");
return;
}
[self sortBannerQueue];
// 从队列中取出第一个元素并移出队列
AttachmentModel *nextAttachment = [self.roomBannertModelsQueueV2 firstObject];
if (self.roomBannertModelsQueueV2.count > 0) {
[self.roomBannertModelsQueueV2 xpSafeRemoveObjectAtIndex:0];
}
// 设置为正在显示的状态
self.isRoomBannerV2Displaying = YES;
NSLog(@"🔄 设置状态为正在显示: %@", NSStringFromClass([nextAttachment class]));
// 清理之前的banner防止多个banner同时显示保留debug视图
NSMutableArray *viewsToRemove = [NSMutableArray array];
for (UIView *subview in self.bannerContainer.subviews) {
[viewsToRemove addObject:subview];
NSLog(@"🔄 标记移除banner: %@", NSStringFromClass([subview class]));
}
for (UIView *view in viewsToRemove) {
[view removeFromSuperview];
}
switch (nextAttachment.second) {
case Custom_Message_Sub_General_Floating_Screen_One_Room:
case Custom_Message_Sub_General_Floating_Screen_All_Room:
// 通用飘屏
[self playGameBanner:nextAttachment];
break;
case Custom_Message_Sub_Super_Gift_Winning_Coins_ALL_Room:
[self playLuckyWinningBanner:nextAttachment];
break;
case Custom_Message_Sub_CP_Gift:
[self playCPGiftBanner:nextAttachment];
break;
case Custom_Message_Sub_CP_Upgrade:
[self playCPLevelUp:nextAttachment];
break;
case Custom_Message_Sub_CP_Binding:
[self playCPBinding:nextAttachment];
break;
case Custom_Message_Sub_Gift_ChannelNotify:
[self playRoomGiftBanner:nextAttachment];
break;
case Custom_Message_Sub_LuckyPackage:
[self playLuckyPackageBanner:nextAttachment];
break;
case Custom_Message_Sub_Super_Gift_Banner:
[self playBroveBanner:nextAttachment];
break;
default:
break;
}
}
- (void)playBroveBanner:(AttachmentModel *)obj {
if (!obj.data) {
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
return;
}
self.isRoomBannerV2Displaying = YES;
@kWeakify(self);
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
[BravoGiftBannerView display:self.bannerContainer
inRoomUid:roomInfo.uid
with:obj
complete:^{
@kStrongify(self);
NSLog(@"🔄 BravoGiftBannerView complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
} exitCurrentRoom:^{
@kStrongify(self);
[self.hostDelegate exitRoom];
}];
}
- (void)playLuckyPackageBanner:(AttachmentModel *)obj {
if (!obj.data) {
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
return;
}
self.isRoomBannerV2Displaying = YES;
@kWeakify(self);
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
[LuckyPackageBannerView display:self.bannerContainer
inRoomUid:roomInfo.uid
with:obj
complete:^{
@kStrongify(self);
NSLog(@"🔄 LuckyPackageBannerView complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
} exitCurrentRoom:^{
@kStrongify(self);
[self.hostDelegate exitRoom];
}];
}
- (void)receiveRoomGiftBanner:(AttachmentModel *)obj {
[self inserBannerModelToQueue:obj];
}
- (void)playRoomGiftBanner:(AttachmentModel *)obj {
if (!obj.data) {
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
return;
}
self.isRoomBannerV2Displaying = YES;
@kWeakify(self);
[RoomHighValueGiftBannerAnimation display:self.bannerContainer
with:obj
complete:^{
@kStrongify(self);
NSLog(@"🔄 RoomHighValueGiftBannerAnimation complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
}];
}
- (void)receiveCPEvent:(AttachmentModel *)attachment {
[self inserBannerModelToQueue:attachment];
}
- (void)playCPBinding:(AttachmentModel *)attachment {
@kWeakify(self);
[CPBindingAnimation display:self.topContainer
with:attachment
complete:^{
@kStrongify(self);
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
}];
}
- (void)playCPGiftBanner:(AttachmentModel *)attachMent {
@kWeakify(self);
[CPGiftBanner display:self.bannerContainer
with:attachMent
complete:^{
@kStrongify(self);
NSLog(@"🔄 CPGiftBanner complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
}];
}
- (void)playCPLevelUp:(AttachmentModel *)attachMent {
@kWeakify(self);
[CPLevelUpAnimation display:self.topContainer
with:attachMent
complete:^{
@kStrongify(self);
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
}];
}
- (void)receiveLuckGiftWinning:(AttachmentModel *)attachment {
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
[LuckyGiftWinningFlagView display:self.topContainer
with:attachment
roomID:roomInfo.roomId
uID:[AccountInfoStorage instance].getUid];
}
- (void)receiveBravoGiftWinning:(AttachmentModel *)attachment {
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
BravoGiftWinningFlagViewModel *flagModel = [BravoGiftWinningFlagView display:self.topContainer
with:attachment
roomID:roomInfo.roomId
uID:[AccountInfoStorage instance].getUid];
if (flagModel.roomId != roomInfo.roomId || flagModel.uid != [AccountInfoStorage instance].getUid.integerValue) {
return;
}
if ([flagModel.receiverUidList containsObject:@([AccountInfoStorage instance].getUid.integerValue)]) {
// 数据同步到 combo
[[NSNotificationCenter defaultCenter] postNotificationName:@"receiveLuckGiftWinning" object:[NSString stringByRemovingRedundantZeros:@(flagModel.receiverProfit).stringValue]];
}
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {
return;
}
NSDictionary *tip = [attachment.data objectForKey:@"tip"];
if (tip) {
NSNumber *level = [tip objectForKey:@"level"];
NSNumber *coins = [tip objectForKey:@"coins"];
if (level) {
[self loadBroveSVGAVideoItem:level.integerValue];
}
if (coins) {
[[NSNotificationCenter defaultCenter] postNotificationName:@"receiveLuckGiftWinning" object:[NSString stringByRemovingRedundantZeros:coins.stringValue]];
}
}
}
- (void)loadBroveSVGAVideoItem:(NSInteger)level {
if (level < 3) {
return;
}
NSString *svgaItemName = @"";
SVGAVideoEntity *entity;
svgaItemName = @"";
entity = self.broveSVGAEntity_lv_3;
/*
switch (level) {
case 1:
svgaItemName = @"小";
entity = self.broveSVGAEntity_lv_1;
break;
case 2:
svgaItemName = @"中";
entity = self.broveSVGAEntity_lv_2;
break;
case 3:
svgaItemName = @"大";
entity = self.broveSVGAEntity_lv_3;
break;
default:
break;
}
*/
if ([NSString isEmpty:svgaItemName]) {
return;
}
if (self.broveSVGAQueue.count >=3) {
return;
}
SVGAImageView *svgaView = [[SVGAImageView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
svgaView.backgroundColor = [UIColor clearColor];
svgaView.contentMode = UIViewContentModeScaleAspectFill;
svgaView.userInteractionEnabled = NO;
if (!entity) {
@kWeakify(self);
SVGAParser *parser = [[SVGAParser alloc] init];
[parser parseWithNamed:svgaItemName
inBundle:[NSBundle mainBundle]
completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
@kStrongify(self);
self.broveSVGAEntity_lv_3 = videoItem;
/*
switch (level) {
case 1:
self.broveSVGAEntity_lv_1 = videoItem;
break;
case 2:
self.broveSVGAEntity_lv_2 = videoItem;
break;
case 3:
self.broveSVGAEntity_lv_3 = videoItem;
break;
default:
break;
}
*/
[self startPlayBroveSVGA:svgaView level:level];
} failureBlock:^(NSError * _Nonnull error) {
}];
} else {
[self startPlayBroveSVGA:svgaView level:level];
}
}
- (void)startPlayBroveSVGA:(SVGAImageView *)svgaView level:(NSInteger)level {
if (!_broveSVGAQueue) {
_broveSVGAQueue = [[NSMutableArray alloc] init];
self.viewIndex = 0;
}
if (![self.broveSVGAQueue containsObject:svgaView]) {
[self.broveSVGAQueue addObject:svgaView];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((0.3 + (self.viewIndex * 0.1)) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
SVGAVideoEntity *entity;
switch (level) {
case 1:
entity = self.broveSVGAEntity_lv_1;
break;
case 2:
entity = self.broveSVGAEntity_lv_2;
break;
case 3:
entity = self.broveSVGAEntity_lv_3;
break;
default:
break;
}
// [self insertSubview:svgaView atIndex:self.viewIndex];
[self _addSubviewToMiddleContainer:svgaView];
svgaView.tag = 913;
svgaView.delegate = self;
svgaView.videoItem = entity;
svgaView.loops = 1;
[svgaView startAnimation];
self.viewIndex += 1;
});
}
- (void)receiveLuckGiftBanner:(AttachmentModel *)attachment {
[self inserBannerModelToQueue:attachment];
}
- (void)playLuckyWinningBanner:(AttachmentModel *)nextAttachment {
RoomInfoModel *roomInfo = self.hostDelegate.getRoomInfo;
@kWeakify(self);
[LuckyGiftWinningBannerView display:self.bannerContainer
inRoomUid:roomInfo.uid
with:nextAttachment
complete:^{
@kStrongify(self);
NSLog(@"🔄 LuckyGiftWinningBannerView complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
} exitCurrentRoom:^{
@kStrongify(self);
[self.hostDelegate exitRoom];
}];
}
-(void)receiveRoomGeneralFloatingScreen:(AttachmentModel *)attachment{
PIBaseAnimationViewModel *roomGraffiti = [PIBaseAnimationViewModel new];
roomGraffiti.data = attachment.data;
roomGraffiti.type = GiftBannerType_General_Floating_Screen;
roomGraffiti.first = attachment.first;
roomGraffiti.second = attachment.second;
PIUniversalBannerModel *model = [PIUniversalBannerModel modelWithDictionary:attachment.data];
if (model.skipType == 7 &&
(attachment.second == Custom_Message_Sub_General_Floating_Screen_One_Room ||
attachment.second == Custom_Message_Sub_General_Floating_Screen_All_Room)) {
[self receiveGameBanner:attachment];
} else {
if(self.animationListB.count == 0 && self.isPlayOfB == NO){
[self createGeneralFloatingScreenAnimation:roomGraffiti bannerModel:model];
}
[self.animationListB addObject:roomGraffiti];
}
}
- (void)receiveGameBanner:(AttachmentModel *)attachment {
[self inserBannerModelToQueue:attachment];
}
- (void)playGameBanner:(AttachmentModel *)attachment {
@kWeakify(self);
[GameUniversalBannerView display:self.bannerContainer
with:attachment
complete:^{
@kStrongify(self);
NSLog(@"🔄 GameUniversalBannerView complete 回调被调用");
self.isRoomBannerV2Displaying = NO;
[self processNextRoomEffectAttachment];
} goToGame:^(NSInteger gameID) {
@kStrongify(self);
NSArray *baishunList = [self.hostDelegate getPlayList];
for (ActivityInfoModel *model in baishunList) {
if (model.id == gameID) {
MSRoomGameWebVC *vc = [[MSRoomGameWebVC alloc]initWithDelegate:self.hostDelegate
gameModel:model];
vc.view.frame = CGRectMake(0, 0, KScreenWidth, KScreenHeight);
XPRoomViewController *roomVC = (XPRoomViewController *)self.hostDelegate;
[roomVC addChildViewController:vc];
RoomAnimationView *animationView;
for (id obj in self.hostDelegate.getSuperView.subviews) {
if ([obj isKindOfClass:[RoomAnimationView class]]){
animationView = obj;
break;
}
}
[self.hostDelegate.getSuperView addSubview:vc.view];
vc.view.tag = 913;
break;
}
}
}];
}
#pragma mark - Method: Car
- (void)handleCarEnter:(AttachmentModel *)attachment {
if (attachment.second == Custom_Message_Sub_Car_EnterRoom) {
if (self.isPlayingGiftEffect) {
return;
}
if ([self _isInSudGame]) {
return;
}
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {
return;
}
if (self.hostDelegate.getUserInfo.platformRole == 1) {
return;
}
NSInteger otherViewType = [attachment.data[@"otherViewType"] integerValue];
NSString *viewUrl = attachment.data[@"viewUrl"];
NSString *effect = attachment.data[@"effect"];
NSDictionary *dic = nil;
if (![NSString isEmpty:viewUrl]) {
dic = @{@"otherViewType":@(otherViewType), @"viewUrl":viewUrl};
} else if(![NSString isEmpty:effect]) {
dic = @{@"effect":effect};
}
[self starHandleCarEffect:dic];
}
}
- (void)starHandleCarEffect:(NSDictionary *)dic {
if (!dic) {
return;
}
[self.carEffectQueue addObject:dic];
[self playCarEffect:dic];
}
- (void)nextCarEffect {
if (self.carEffectQueue.count > 0) {
if (self.carEffectQueue.count > 0) {
[self.carEffectQueue xpSafeRemoveObjectAtIndex:0];
}
}
if (self.carEffectQueue.count > 0) {
[self playCarEffect:self.carEffectQueue.firstObject];
}
}
- (void)playCarEffect:(NSDictionary *)effectDict {
NSString *viewUrl = [effectDict objectForKey:@"viewUrl"];
NSString *carEffect = [effectDict objectForKey:@"effect"];
@kWeakify(self);
if (![NSString isEmpty:viewUrl]) {
[self.vapParser parseWithURL:viewUrl completionBlock:^(NSString * _Nullable videoUrl) {
@kStrongify(self);
if (![NSString isEmpty:videoUrl]) {
if([videoUrl.lowercaseString containsString:@".pag"]){
self.carPagEffectView.hidden = NO;
[self _addSubviewToMiddleContainer:self.carPagEffectView];
[self.carPagEffectView setPath:videoUrl];
[self.carPagEffectView play];
} else {
self.carVapEffectView.hidden = NO;
[self _addSubviewToMiddleContainer:self.carVapEffectView];
[self.carVapEffectView setMute:NO];
[self.carVapEffectView playHWDMP4:videoUrl repeatCount:1 delegate:self];
}
}
} failureBlock:^(NSError * _Nullable error) {
@kStrongify(self);
[self nextCarEffect];
}];
} else if (![NSString isEmpty:carEffect]) {
[self.vggParser parseWithURL:[NSURL URLWithString:carEffect]
completionBlock:^(SVGAVideoEntity * _Nullable videoItem) {
@kStrongify(self);
if (videoItem) {
[self _addSubviewToMiddleContainer:self.carSVGAEffectView];
[self _updateGiftEffectContentMode:self.carSVGAEffectView
size:videoItem.videoSize];
self.carSVGAEffectView.videoItem = videoItem;
[self.carSVGAEffectView startAnimation];
}
} failureBlock:^(NSError * _Nullable error) {
@kStrongify(self);
[self nextCarEffect];
}];
}
}
#pragma mark - Method: Send Gifts
- (void)receiveGiftHandleSendGiftAnimationWith:(GiftReceiveInfoModel *)receiveInfo attachment:(AttachmentModel *)attachment {
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {
return;
}
GiftInfoModel *giftInfo = receiveInfo.gift;
if (attachment.second == Custom_Message_Sub_AllMicroLuckySend ||
attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend ||
attachment.second == Custom_Message_Sub_Gift_LuckySend) {
NSString * giftId = [NSString stringWithFormat:@"%ld", receiveInfo.luckyGiftList.giftList.firstObject.giftId];
NSString *roomUid = receiveInfo.roomUid == 0 ? receiveInfo.uid : @(receiveInfo.roomUid).stringValue;
giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:giftId inRoom:roomUid];
}
if (giftInfo == nil) {
giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:receiveInfo.giftId inRoom:@(receiveInfo.roomUid).stringValue];
}
if (giftInfo == nil) {
giftInfo = [receiveInfo.displayGift xpSafeObjectAtIndex:0];
}
receiveInfo.gift = giftInfo;
RoomInfoModel * roomInfo = [self.hostDelegate getRoomInfo];
if ((giftInfo.otherViewType == GiftOtherViewTypeMp4 ||
giftInfo.otherViewType == GiftOtherViewTypePag) &&
giftInfo.viewUrl.length > 0 && roomInfo.hasAnimationEffect) {
receiveInfo.mp4Url = giftInfo.viewUrl;
} else if (giftInfo.hasVggPic &&
giftInfo.vggUrl.length > 0
&& roomInfo.hasAnimationEffect) {///SVGA动画
receiveInfo.vggUrl = giftInfo.vggUrl;
}
if (attachment.second != Custom_Message_Sub_Gift_EmbeddedStyle) {
// Custom_Message_Sub_Gift_EmbeddedStyle 只需播放特效
[self.giftAnimationManager enqueueGift:receiveInfo];
}
}
- (void)receiveGift:(GiftReceiveInfoModel *)receiveInfo {
if (receiveInfo.isHomeShow) {
return;
}
// 处理 combo
[[GiftComboManager sharedManager] receiveGiftInfoForDisplayComboFlags:receiveInfo
container:self];
if (receiveInfo.isLuckyBagGift) {
if (receiveInfo.isShowAnimation) {
[self handleLuckyBagGifts:receiveInfo];
}
} else {
if (![NSString isEmpty:receiveInfo.mp4Url] || ![NSString isEmpty:receiveInfo.vggUrl]) {
[self addToSvgaQueue:receiveInfo];
}
}
dispatch_async(self.giftEffectsQueue, ^{
if (self.giftEffectTimer == nil &&
self.svgaQueue.count > 0) {
[self startHandleGiftEffectTimer];
}
});
}
- (void)handleLuckyBagGifts:(GiftReceiveInfoModel *)receiveInfo {
//如果是福袋礼物的话 就不用看他的价值了 只要有SVGA的话 就播放
// MARK: 此代码从 XPRoomAnimationView copy 而来,暂时无法确认其正确性
RoomInfoModel * roomInfo = [self.hostDelegate getRoomInfo];
if (receiveInfo.displayGift.count > 0) {
[receiveInfo.displayGift enumerateObjectsUsingBlock:^(GiftInfoModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ((obj.otherViewType == GiftOtherViewTypeMp4 || obj.otherViewType == GiftOtherViewTypePag) && obj.viewUrl && obj.viewUrl.length > 0 && roomInfo.hasAnimationEffect) {
GiftReceiveInfoModel * model = [[GiftReceiveInfoModel alloc] init];
model.mp4Url = obj.viewUrl;
model.avatar = receiveInfo.sendUserAvatar;
model.gift = obj;
model.giftNum = [obj.giftNum integerValue];;
model.nick = receiveInfo.nick;
model.targetUids = receiveInfo.targetUids;
model.isBatch = receiveInfo.isBatch;
model.targetAvatar = receiveInfo.targetAvatar;
model.targetNick = receiveInfo.targetNick;
[self addToSvgaQueue:model];
} else if (obj.hasVggPic && roomInfo.hasAnimationEffect) {
GiftReceiveInfoModel * model = [[GiftReceiveInfoModel alloc] init];
model.mp4Url = obj.viewUrl;
model.avatar = receiveInfo.sendUserAvatar;
model.gift = obj;
model.giftNum = [obj.giftNum integerValue];;
model.nick = receiveInfo.nick;
model.targetUids = receiveInfo.targetUids;
model.isBatch = receiveInfo.isBatch;
model.targetAvatar = receiveInfo.targetAvatar;
model.targetNick = receiveInfo.targetNick;
[self addToSvgaQueue:model];
}
}];
}
}
- (void)startHandleGiftEffectTimer {
NSTimeInterval period = 2.0;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒执行
@kWeakify(self);
dispatch_source_set_event_handler(timer, ^{
@kStrongify(self)
if (!self) {
return;
}
dispatch_async(self.giftEffectsQueue, ^{
NSLog(@"******************* 当前队列个数: %@image loader 个数: %@", @(self.svgaQueue.count), @(self.mp4AvatarLoaders.count));
if (self.svgaQueue.count == 0) {
dispatch_source_cancel(timer);
dispatch_async(dispatch_get_main_queue(), ^{
self.giftEffectTimer = nil;
});
} else {
if (self.isPlayingGiftEffect == NO) {
self.isPlayingGiftEffect = YES;
GiftReceiveInfoModel *receiveModel = [self.svgaQueue xpSafeObjectAtIndex:0];
if ([receiveModel isKindOfClass:[GiftReceiveInfoModel class]]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self createGiftSvgaAnimation:receiveModel];
});
}else {
[self removeFromSvgaQueueAtIndex:0];
self.isPlayingGiftEffect = NO;
}
}
}
});
});
self.giftEffectTimer = timer;
dispatch_resume(timer);
}
-(void)createGiftSvgaAnimation:(GiftReceiveInfoModel *)receiveInfo {
GiftInfoModel *giftInfo = receiveInfo.gift;
NSString *targetURL = @"";
if (receiveInfo.isLuckyBagGift) {
// 播放背包礼物动画
if (![NSString isEmpty:receiveInfo.mp4Url]) {
[self stopCarEffect:giftInfo.goldPrice];
targetURL = receiveInfo.mp4Url;
[self playLuckyGiftEffectWithVapUrl:receiveInfo.mp4Url];
} else if (![NSString isEmpty:receiveInfo.luckyGiftSvgaUrl]) {
[self stopCarEffect:giftInfo.goldPrice];
targetURL = receiveInfo.luckyGiftSvgaUrl;
[self playGiftEffectWithVapUrl:receiveInfo.luckyGiftSvgaUrl];
} else if (![NSString isEmpty:giftInfo.luckyGiftSvgaUrl]) {
[self stopCarEffect:giftInfo.goldPrice];
targetURL = giftInfo.luckyGiftSvgaUrl;
[self playGiftEffectWithVapUrl:giftInfo.luckyGiftSvgaUrl];
}
} else {
[self stopCarEffect:giftInfo.goldPrice];
if (giftInfo.otherViewType == GiftOtherViewTypePag ||
giftInfo.otherViewType == GiftOtherViewTypeMp4) {
if (giftInfo.otherViewType == GiftOtherViewTypePag) {
[self playGiftEffectWithPagUrl:giftInfo.viewUrl];
targetURL = giftInfo.viewUrl;
} else {
self.mp4TempReceiveInfoModel = receiveInfo;
[self playGiftEffectWithVapUrl:giftInfo.viewUrl];
targetURL = giftInfo.viewUrl;
}
}
// 兜底,同时判断是否可以执行 svga
if ([NSString isEmpty:targetURL] && giftInfo.hasVggPic && giftInfo.vggUrl.length > 0) {
[self playGiftEffectWithVggUrl:giftInfo.vggUrl];
targetURL = giftInfo.vggUrl;
}
}
// NSLog(@"******************* 执行播放, 是否MP4:%@URL: %@, self.svgaQueue num: %@", @(giftInfo.otherViewType), targetURL, @(self.svgaQueue.count));
[[NSNotificationCenter defaultCenter] postNotificationName:@"kExchangeRoomAnimationViewAndGameViewIndex"
object:nil];
@kWeakify(self);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
@kStrongify(self);
[self removeFromSvgaQueueAtIndex:0];
});
}
- (void)stopCarEffect:(double)goldPrice {
if ([ClientConfig shareConfig].configInfo.hideCarEffectGiftPrice <= goldPrice) {
[self.carEffectQueue removeAllObjects];
[self.carSVGAEffectView stopAnimation];
[self.carVapEffectView stopHWDMP4];
[self.carPagEffectView stop];
}
}
- (void)playGiftEffectWithPagUrl:(NSString *)pagUrl {
@kWeakify(self);
[self.vapParser parseWithURL:pagUrl
completionBlock:^(NSString * _Nullable videoUrl) {
@kStrongify(self);
if ([NSString isEmpty:videoUrl]) {
[self playPAGFailure];
} else {
[self _addSubviewToMiddleContainer:self.pagGiftEffectView];
[self.pagGiftEffectView setPath:videoUrl];
[self.pagGiftEffectView play];
}
} failureBlock:^(NSError * _Nullable error) {
@kStrongify(self);
[self playPAGFailure];
}];
}
- (void)playGiftEffectWithVapUrl:(NSString *)vapUrl {
NSString *encodingUrl = [vapUrl pureURLString];
NSString *fullPath = [self _findFullPath:vapUrl];
self.mp4AvatarLoaders = @[].mutableCopy;
if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]){
[self playVAG:fullPath];
}else {
@kWeakify(self);
[self.vapParser parseWithURL:encodingUrl
completionBlock:^(NSString * _Nullable videoUrl) {
@kStrongify(self);
if ([NSString isEmpty:videoUrl]) {
[self playVAGFailure];
} else {
[self playVAG:videoUrl];
}
} failureBlock:^(NSError * _Nullable error) {
@kStrongify(self);
[self playVAGFailure];
}];
}
}
- (void)playGiftEffectWithVggUrl:(NSString *)vggUrl {
NSString *encodingUrl = [vggUrl pureURLString];
NSString *fullPath = [self _findFullPath:vggUrl];
// NSLog(@"******************* 解释 SVGA : %@ | %@", encodingUrl, fullPath);
if (![NSString isEmpty:fullPath] && [[NSFileManager defaultManager] fileExistsAtPath:fullPath]) {
NSData *data = [NSData dataWithContentsOfFile:fullPath options:0 error:NULL];
NSString *fileName = [[encodingUrl componentsSeparatedByString:@"/"] lastObject];
@kWeakify(self);
[self.vggParser parseWithData:data
cacheKey:fileName
completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
@kStrongify(self);
if (videoItem) {
[self playVGG:videoItem];
} else {
[self playVGGFailure];
}
} failureBlock:^(NSError * _Nonnull error) {
@kStrongify(self);
[self playVGGFailure];
}];
} else {
@kWeakify(self);
[self.vggParser parseWithURL:[NSURL URLWithString:encodingUrl]
completionBlock:^(SVGAVideoEntity * _Nullable videoItem) {
@kStrongify(self);
// NSLog(@"******************* 解释 SVGA 成功");
if (videoItem) {
[self playVGG:videoItem];
} else {
[self playVGGFailure];
}
} failureBlock:^(NSError * _Nullable error) {
@kStrongify(self);
// NSLog(@"******************* 解释 SVGA 失败:%@", error);
[self playVGGFailure];
}];
}
}
- (void)playVGG:(SVGAVideoEntity *)videoItem {
[self.vggGiftEffectView stopAnimation];
[self _addSubviewToMiddleContainer:self.vggGiftEffectView];
[self _updateGiftEffectContentMode:self.vggGiftEffectView
size:videoItem.videoSize];
self.vggGiftEffectView.videoItem = videoItem;
[self.vggGiftEffectView startAnimation];
}
- (void)playVGGFailure {
[self playVGGEnd];
}
- (void)playVGGEnd {
self.isPlayingGiftEffect = NO;
self.vggGiftEffectView.hidden = YES;
}
- (void)playVAG:(NSString *)url {
@kWeakify(self);
dispatch_async(dispatch_get_main_queue(), ^{
@kStrongify(self);
[self _addSubviewToMiddleContainer:self.vapGiftEffectView];
[self.vapGiftEffectView setMute:NO];
[self.vapGiftEffectView playHWDMP4:url
repeatCount:1
delegate:self];
});
}
- (void)playVAGFailure {
[self playVAGEnd];
}
- (void)playVAGEnd {
self.isPlayingGiftEffect = NO;
self.vapGiftEffectView.hidden = YES;
[self.vapGiftEffectView setMute:YES];
[self.vapGiftEffectView stopHWDMP4];
[self.vapGiftEffectView removeFromSuperview];
self.vapGiftEffectView = nil;
}
- (void)playPAGFailure {
self.isPlayingGiftEffect = NO;
self.pagGiftEffectView.hidden = YES;
}
#pragma mark - Delegates
#pragma mark - SVGA delegate
- (void)svgaPlayerDidFinishedAnimation:(SVGAPlayer *)player {
if (player.tag == 913) {
[player clear];
player.delegate = nil;
[player removeFromSuperview];
self.viewIndex -= 1;
if ([self.broveSVGAQueue containsObject:player]) {
[self.broveSVGAQueue removeObject:player];
}
return;
}
if (player == self.enterEffectView && player.loops == 1) {
[self endAnimationEnterEffect];
}
else if (player == self.vggGiftEffectView) {
[self playVGGEnd];
}
else if (player == self.carSVGAEffectView) {
self.carSVGAEffectView.hidden = YES;
[self.carSVGAEffectView removeFromSuperview];
[self nextCarEffect];
}
}
#pragma mark - HWDMP4PlayDelegate
- (BOOL)shouldStartPlayMP4:(VAPView *)container config:(QGVAPConfigModel *)config {
CGFloat width = config.info.size.width;
CGFloat height = config.info.size.height;
container.center = self.center;
[container mas_updateConstraints:^(MASConstraintMaker *make) {
make.width.mas_equalTo(KScreenWidth);
make.height.mas_equalTo(KScreenWidth * height / width);
}];
return YES;
}
- (void)viewDidFinishPlayMP4:(NSInteger)totalFrameCount view:(VAPView *)container {
dispatch_async(dispatch_get_main_queue(), ^{
container.hidden = YES;
if (container == self.carVapEffectView) {
[self.carVapEffectView removeFromSuperview];
self.carVapEffectView = nil;
[self nextCarEffect];
}
else if (container == self.vapGiftEffectView) {
[self playVAGEnd];
}
else if(container == self.luckyVapGiftEffectView) {
[self.luckyVapGiftEffectView removeFromSuperview];
self.luckyVapGiftEffectView = nil;
}
});
}
- (void)viewDidStopPlayMP4:(NSInteger)lastFrameIndex view:(VAPView *)container {
dispatch_async(dispatch_get_main_queue(), ^{
container.hidden = YES;
if (container == self.carVapEffectView) {
[self.carVapEffectView removeFromSuperview];
[self nextCarEffect];
}
else if (container == self.vapGiftEffectView) {
[self playVAGEnd];
}
else if(container == self.luckyVapGiftEffectView) {
[self.luckyVapGiftEffectView removeFromSuperview];
self.luckyVapGiftEffectView = nil;
}
});
}
- (void)viewDidFailPlayMP4:(NSError *)error{
[self playVAGFailure];
}
- (void)loadVapImageWithURL:(NSString *)urlStr
context:(NSDictionary *)context
completion:(VAPImageCompletionBlock)completionBlock {
if (self.mp4TempReceiveInfoModel) {
dispatch_async(dispatch_get_main_queue(), ^{
QGVAPSourceInfo *info = (QGVAPSourceInfo *)context[@"resource"];
// NSLog(@" MP4 的 key - info.contentTag : %@", info.contentTag);
[self _loadMP4AvatarURL:urlStr
info:info
completion:completionBlock];
});
}
}
- (void)_loadMP4AvatarURL:(NSString *)urlStr
info:(QGVAPSourceInfo *)info
completion:(VAPImageCompletionBlock)completionBlock {
NSString *path = @"";
switch (self.mp4TempReceiveInfoModel.gift.showAvatarType) {
case 1: // 只使用 avatar
case 3:
path = self.mp4TempReceiveInfoModel.avatar;
if ([NSString isEmpty:path]) {
path = self.mp4TempReceiveInfoModel.sendUserAvatar;
}
break;
case 2: // 只使用 target avatar
path = self.mp4TempReceiveInfoModel.targetAvatar;
if ([NSString isEmpty:path]) {
path = self.mp4TempReceiveInfoModel.recvUserAvatar;
}
break;
default:
break;
}
if ([NSString isEmpty:path]) {
completionBlock(kImage(@"common_avatar"), nil, @"dafeult image");
} else {
NetImageView *avatar_Loader = [[NetImageView alloc] init];
[avatar_Loader loadImageWithUrl:path
completion:^(UIImage * _Nullable image, NSURL * _Nonnull url) {
completionBlock(image, nil, urlStr);
}];
[self.mp4AvatarLoaders addObject:avatar_Loader];
}
}
#pragma mark - PAGViewListener
- (void)onAnimationEnd:(PAGView*)pagView{
dispatch_async(dispatch_get_main_queue(), ^{
pagView.hidden = YES;
if (pagView == self.pagGiftEffectView) {
self.isPlayingGiftEffect = NO;
}
else if(pagView == self.carPagEffectView){
[self.carPagEffectView removeFromSuperview];
self.carPagEffectView = nil;
[self nextCarEffect];
}
});
}
- (void)onAnimationCancel:(PAGView*)pagView{
dispatch_async(dispatch_get_main_queue(), ^{
pagView.hidden = YES;
if (pagView == self.pagGiftEffectView) {
self.isPlayingGiftEffect = NO;
}
});
}
#pragma mark - RoomHostDelegate
#pragma mark - RoomGuestDelegate: NIMCustomMessage
- (void)handleNIMCustomMessage:(NIMMessage *)message {
if (![message.messageObject isKindOfClass:[NIMCustomObject class]]) {
return;
}
NIMCustomObject *obj = (NIMCustomObject *)message.messageObject;
if (obj.attachment == nil || ![obj.attachment isKindOfClass:[AttachmentModel class]]) {
return;
}
AttachmentModel *attachment = (AttachmentModel *)obj.attachment;
{
// 自定义消息处理入口排查日志first/second、payload size、线程
NSData *payloadJSON = nil;
@try { payloadJSON = [NSJSONSerialization dataWithJSONObject:attachment.data ?: @{} options:0 error:nil]; } @catch (__unused NSException *e) {}
NSLog(@"[Combo effect][Anim] 🎞 handleNIMCustomMessage | first=%ld second=%ld | payload=%lub | main=%@ | ts=%.3f",
(long)attachment.first, (long)attachment.second,
(unsigned long)payloadJSON.length,
[NSThread isMainThread] ? @"YES" : @"NO",
[[NSDate date] timeIntervalSince1970]);
}
switch (attachment.first) {
case CustomMessageType_User_Enter_Room:
[self _handleEnterRoomMessage:message];
break;
case CustomMessageType_RedPacket:
[self _handleLuckyPackageMessage:attachment];
break;
case CustomMessageType_Gift:
[self _handleGiftMessage:attachment];
break;
case CustomMessageType_AllMicroSend:
[self _handleGiftMessage:attachment];
break;
case CustomMessageType_Car_Notify:
[self handleCarEnter:attachment];
break;
case CustomMessageType_CP:
[self receiveCPEvent:attachment];
break;
case CustomMessageType_Super_Gift:
[self _handleSuperGift:attachment];
break;
case CustomMessageType_General_Floating_Screen:
[self _handleCommonBanner:attachment];
break;
case CustomMessageType_LuckyBag:
[self handleLuckyBag:attachment];
break;
case CustomMessageType_Look_Love:
[self handle98:attachment];
break;
case CustomMessageType_RoomPlay_Dating:
[self handleDating:attachment];
break;
case CustomMessageType_Across_Room_PK:
[self handleAcrossRoomPK:attachment];
break;
case CustomMessageType_Anchor_FansTeam:
[self handleAnchorFansTeam:attachment];
break;
case CustomMessageType_Anchor_Hour_Rank:
[self handleAnchorHourRank:attachment];
break;
case CustomMessageType_License_Hour_Rank:
[self handleLicenseHourRank:attachment];
break;
case CustomMessageType_Gift_Compound:
[self handle93:attachment];
break;
case CustomMessageType_Room_Sailing:
[self handle81:attachment];
break;
case CustomMessageType_Graffiti_Gift: {
[self receiveRoomGraffitiGift:attachment];
}
break;
case CustomMessageType_Graffiti_Star_Kitchen:
[self handle104:attachment];
break;
case CustomMessageType_Treasure_Fairy:
[self handleFairy:attachment];
break;
case CustomMessageType_Tarot:
[self handleTarot:attachment];
break;
case CustomMessageType_Common_H5:
[self handleCommonH5:attachment];
break;
default:
break;
}
}
- (void)_handleEnterRoomMessage:(NIMMessage *)message {
NIMCustomObject *obj = (NIMCustomObject *)message.messageObject;
if (obj.attachment == nil || ![obj.attachment isKindOfClass:[AttachmentModel class]]) {
return;
}
AttachmentModel *attachment = (AttachmentModel *)obj.attachment;
switch (attachment.second) {
case Custom_Message_Sub_User_Enter_Room: {
RoomEnterModel *model = [RoomEnterModel modelWithJSON:attachment.data];
if (model.platformRole == 1) {
return;
}
if (model.enterHide) {
//隐身进房
if (model.uid == [AccountInfoStorage instance].getUid.integerValue) {
[self createEnterHideAnimation];
}
} else {
NSString *userName = model.nick;
if (model.cpList.count > 0 && model.screenType < 3) {
NSString *title = [NSString stringWithFormat:YMLocalizedString(@"XPRoomAnimationView0"), userName];
NSDictionary * dic= @{@"title":title,
@"experLevelSeq":[NSString stringWithFormat:@"%ld", model.experLevelSeq],
@"effectPath" : @"",
@"isCP":@(YES)
};
[self.enterRoomAnimationQueue addObject:dic];
} else {
NSString *title = [NSString stringWithFormat:YMLocalizedString(@"XPRoomAnimationView0"), userName];
NSDictionary * dic= @{@"title":title,
@"experLevelSeq":[NSString stringWithFormat:@"%ld", model.experLevelSeq],
@"effectPath" : model.enterRoomEffects.length ? model.enterRoomEffects : @""};
[self.enterRoomAnimationQueue addObject:dic];
}
[self tryDequeueAnimation];
}
}
break;
default:
break;
}
}
- (void)_handleLuckyPackageMessage:(AttachmentModel *)attachment {
if ([self _isInSudGame]) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_LuckyPackage:
[self receiveLuckGiftBanner:attachment];
break;
default:
return;
break;
}
}
- (void)_handleGiftMessage:(AttachmentModel *)attachment {
if ([self _isInSudGame]) {
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);
receiveInfo.isBatch = (attachment.second == Custom_Message_Sub_AllBatchSend ||
attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend);
receiveInfo.isComboBatch = (attachment.second == Custom_Message_Sub_AllMicroSend);
switch (attachment.second) {
case Custom_Message_Sub_Gift_Send:
[self _handleGift:receiveInfo attachment:attachment];
break;
case Custom_Message_Sub_AllMicroSend:
case Custom_Message_Sub_AllBatchSend:
[self _handleGift:receiveInfo attachment:attachment];
break;
case Custom_Message_Sub_Gift_ChannelNotify:
//处理原广播通用飘屏 banner 逻辑
[self receiveRoomGiftBanner:attachment];
return;
break;
case Custom_Message_Sub_Gift_EmbeddedStyle:
[self _handleGiftEmbeddedStyle:receiveInfo attachment:attachment];
break;
case 607:
[self receiveLuckGiftBanner:attachment];
break;
case Custom_Message_Sub_Gift_LuckySend:
case Custom_Message_Sub_AllMicroLuckySend:
case Custom_Message_Sub_AllBatchMicroLuckySend:
{
[self _handleGift:receiveInfo attachment:attachment];
// if (receiveInfo.mp4Url.length > 0) {
// [self playLuckyGiftEffectWithVapUrl:receiveInfo.mp4Url];
// } else {
// NSString * svgaString = receiveInfo.luckyGiftSvgaUrl.length > 0 ? receiveInfo.luckyGiftSvgaUrl : receiveInfo.gift.luckyGiftSvgaUrl;
// NSURL * luckyGiftSvgaUrl = [NSURL URLWithString:svgaString];
// if (luckyGiftSvgaUrl.absoluteString.length > 0) {
// [self play:luckyGiftSvgaUrl];
// }
// }
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// [self receiveGift:receiveInfo];
// });
}
break;
default:
break;
}
if (receiveInfo.isLuckyBagGift) {
NSLog(@"[Combo effect] 🎁 处理福袋礼物");
[self receiveGiftHandleSendGiftAnimationWith:receiveInfo
attachment:attachment];
[self _handleBagGift:receiveInfo];
} else {
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如果有的话
[self receiveGift:receiveInfo];
}
}
- (void)_handleBagGift:(GiftReceiveInfoModel *)receiveInfo {
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {
return;
}
[self receiveGift:receiveInfo];
}
- (void)_handleGift:(GiftReceiveInfoModel *)receiveInfo
attachment:(AttachmentModel *)attachment {
// 确认接受者有 uid
if (receiveInfo.targetUsers.count == 0) {
GiftReceiveUserInfoModel *model = [[GiftReceiveUserInfoModel alloc] init];
model.nick = receiveInfo.targetNick;
model.avatar = receiveInfo.targetAvatar;
model.uid = receiveInfo.uid.integerValue;
receiveInfo.targetUsers = @[model];
}
// 确认接受者有 uid
if (receiveInfo.targetUsers.count > 0 && receiveInfo.targetUids.count <= 0) {
receiveInfo.targetUids = [receiveInfo.targetUsers valueForKeyPath:@"uid"];
}
}
- (void)_handleGiftEmbeddedStyle:(GiftReceiveInfoModel *)receiveInfo
attachment:(AttachmentModel *)attachment {
// 数据对齐
receiveInfo.targetUid = [[attachment.data objectForKey:@"recvUserUid"] stringValue];
receiveInfo.targetNick = [attachment.data objectForKey:@"recvUserNick"];
receiveInfo.targetAvatar = [attachment.data objectForKey:@"recvUserAvatar"];
receiveInfo.avatar = [attachment.data objectForKey:@"sendUserAvatar"];
receiveInfo.nick = [attachment.data objectForKey:@"sendUserNick"];
receiveInfo.uid = [[attachment.data objectForKey:@"sendUserUid"] stringValue];
// 确认接受者有 uid
if (receiveInfo.targetUsers.count > 0 && receiveInfo.targetUids.count <= 0) {
receiveInfo.targetUids = [receiveInfo.targetUsers valueForKeyPath:@"uid"];
}
}
- (void)_handleSuperGift:(AttachmentModel *)attachment {
switch (attachment.second) {
case Custom_Message_Sub_Super_Gift_Winning_Coins:
[self receiveLuckGiftWinning:attachment];
break;
case Custom_Message_Sub_Super_Gift_Winning_Coins_ALL_Room:
[self receiveLuckGiftBanner:attachment];
break;
case Custom_Message_Sub_Super_Gift_Banner:
[self handleBroveGiftBanner:attachment];
break;
case Custom_Message_Sub_Super_Gift_UI_Rffect:
[self receiveBravoGiftWinning:attachment];
default:
break;
}
}
- (void)_handleCommonBanner:(AttachmentModel *)attachment {
switch (attachment.second) {
case Custom_Message_Sub_General_Floating_Screen_One_Room:
case Custom_Message_Sub_General_Floating_Screen_All_Room:
[self receiveRoomGeneralFloatingScreen:attachment];
break;
default:
break;
}
}
- (NSString *)_findFullPath:(NSString *)url {
NSString *encodingUrl = [url pureURLString];
NSString *fileName = [[encodingUrl componentsSeparatedByString:@"/"] lastObject];
NSString *fullPath = [self.GiftDynamicEffectListPath stringByAppendingPathComponent:fileName];
return fullPath;
}
- (void)_updateGiftEffectContentMode:(UIView *)view
size:(CGSize)size {
CGFloat width = size.width;
CGFloat height = size.height;
if (width > height) {
view.contentMode = UIViewContentModeScaleAspectFit;
} else {//高大于宽
CGFloat resizeH = KScreenWidth * height / width;//按照屏幕的宽度去缩放,获得高度
if (resizeH > KScreenHeight) {//如果大于屏幕高度,填充
view.contentMode = UIViewContentModeScaleAspectFill;
} else {//小于屏幕高度,
view.contentMode = UIViewContentModeScaleAspectFit;
}
}
}
- (void)handleCommonH5:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
default:
break;
}
}
- (void)handleTarot:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
default:
break;
}
}
- (void)handleFairy:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L4:
case Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L5:
case Custom_Message_Sub_Treasure_Fairy_Convert_L1:
case Custom_Message_Sub_Treasure_Fairy_Convert_L2:
case Custom_Message_Sub_Treasure_Fairy_Convert_L3:
[self receiveTreasureFairyGiftHighLevel:attachment];
break;
default:
break;
}
}
- (void)handle98:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_Look_Love_InRoom_NeedAllMicSend:
[self receiveCandyTreeGiftHighLevle:attachment];
break;
default:
break;
}
}
- (void)handle104:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
default:
break;
}
}
- (void)handleLuckyBag:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_Room_Gift_LuckBag_FullScree:
case Custom_Message_Sub_Room_Gift_LuckBag_Server:
[self receiveLuckyGiftBigPrize:attachment];
break;
default:
break;
}
}
- (void)handleVIPLevelUp:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_Room_Noble_LevelUp_Suspend:
[self receiveNobleLevelUp:attachment];
break;
default:
break;
}
}
- (void)handleDating:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_Room_Play_Dating_Public_Result:
[self roomDatingPublicResult:attachment];
break;
default:
break;
}
}
- (void)handleAcrossRoomPK:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_AcrossRoomPK_Result:
[self acrossRoomPKBannerAnimation:attachment];
break;
default:
break;
}
}
- (void)handleAnchorFansTeam:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_FansTeam_Join_Success: {
GiftReceiveInfoModel *receiveInfo = [[GiftReceiveInfoModel alloc] init];
GiftInfoModel *giftInfo = [GiftInfoModel modelWithJSON:attachment.data[@"giftVo"]];
receiveInfo.gift = giftInfo;
receiveInfo.giftInfo = giftInfo;
[self receiveFansTeamGiftHandleSendGiftAnimation:attachment];
[self receiveGift:receiveInfo];
}
break;
default:
break;
}
}
- (void)handleAnchorHourRank:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_Anchor_Hour_Rank:
[self receiveAnchorHourRank:attachment];
break;
default:
break;
}
}
- (void)handleLicenseHourRank:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_License_Hour_Rank:
[self receiveAnchorHourRank:attachment];
break;
default:
break;
}
}
- (void)handle93:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_Gift_Compound:
[self receiveGiftCompound:attachment];
break;
default:
break;
}
}
- (void)handle81:(AttachmentModel *)attachment {
if (!attachment) {
return;
}
switch (attachment.second) {
case Custom_Message_Sub_Sailing_AllRoom_Notify:
case Custom_Message_Sub_Sailing_InRoom_NeedAllMicSend:
[self receiveRoomSailing:attachment];
break;
default:
break;
}
}
- (void)handleBroveGiftBanner:(AttachmentModel *)attachment {
[self inserBannerModelToQueue:attachment];
}
#pragma mark - RoomGuestDelegate: NIMNotificationMessageDelegate
- (void)handleNIMNotificationMessage:(NIMMessage *)message {
return;
// NIMNotificationObject *notiMsg = (NIMNotificationObject *)message.messageObject;
// NIMChatroomNotificationContent *content = (NIMChatroomNotificationContent *)notiMsg.content;
// if (!content) {
// return;
// }
//
// switch (content.eventType) {
// case NIMChatroomEventTypeEnter:
// [self enterRoom:message content:content];
// break;
//
// default:
// break;
// }
}
#pragma mark - NIMBroadcastManagerDelegate
- (void)onReceiveBroadcastMessage:(NIMBroadcastMessage *)broadcastMessage {
if (broadcastMessage.content) {
NSDictionary *msgDictionary = [broadcastMessage.content toJSONObject];
AttachmentModel *attachment = [AttachmentModel modelWithJSON:msgDictionary[@"body"]];
NSString *partitionId = [NSString stringWithFormat:@"%@",attachment.data[@"partitionId"]];
if(![partitionId isEqualToString:self.hostDelegate.getUserInfo.partitionId]){
return;
}
switch (attachment.first) {
case CustomMessageType_General_Floating_Screen:
[self _handleCommonBanner:attachment];
break;
case CustomMessageType_Noble_VIP:
[self handleVIPLevelUp:attachment];
break;
case CustomMessageType_LuckyBag:
[self handleLuckyBag:attachment];
break;
case CustomMessageType_Graffiti_Star_Kitchen:
[self handle104:attachment];
break;
case CustomMessageType_Look_Love:
[self handle98:attachment];
break;
case CustomMessageType_Treasure_Fairy:
[self handleFairy:attachment];
break;
case CustomMessageType_Tarot:
[self handleTarot:attachment];
break;
case CustomMessageType_Common_H5:
[self handleCommonH5:attachment];
break;
default:
break;
}
}
}
#pragma mark - GiftAnimationManagerDelegate
- (CGPoint)animationPointAtStageViewByUid:(NSString *)uid {
return [self.hostDelegate animationPointAtStageViewByUid:uid];
}
#pragma mark - Gesture
- (void)addBnnerContainGesture {
[self insertSubview:self.bannerSwipeGestureContainer aboveSubview:self.bannerContainer];
[self insertSubview:self.bannerLeftTapGestureContainer aboveSubview:self.bannerContainer];
[self insertSubview:self.bannerRightTapGestureContainer aboveSubview:self.bannerContainer];
[self.bannerSwipeGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(self.bannerContainer);
make.top.bottom.mas_equalTo(self.bannerContainer);
make.width.mas_equalTo(self.bannerContainer.mas_width).multipliedBy(2.0/3.0);
}];
[self.bannerLeftTapGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.leading.bottom.mas_equalTo(self.bannerContainer);
make.trailing.mas_equalTo(self.bannerSwipeGestureContainer.mas_leading);
}];
[self.bannerRightTapGestureContainer mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.trailing.bottom.mas_equalTo(self.bannerContainer);
make.leading.mas_equalTo(self.bannerSwipeGestureContainer.mas_trailing);
}];
// 创建中央区域的 swipe 手势2/3 宽度)
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:@selector(handleSwipe)];
if (isMSRTL()) {
swipe.direction = UISwipeGestureRecognizerDirectionRight;
} else {
swipe.direction = UISwipeGestureRecognizerDirectionLeft;
}
swipe.delegate = self;
// 创建中央区域的 tap 手势2/3 宽度)
UITapGestureRecognizer *centerTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleBannerTap:)];
centerTap.delegate = self;
// 创建左侧区域的 tap 手势1/6 宽度)
UITapGestureRecognizer *leftTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleBannerTap:)];
leftTap.delegate = self;
// 创建右侧区域的 tap 手势1/6 宽度)
UITapGestureRecognizer *rightTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(handleBannerTap:)];
rightTap.delegate = self;
// 只有当 swipe 判定失败后tap 才允许成功
[centerTap requireGestureRecognizerToFail:swipe];
// 添加手势识别器
[self.bannerSwipeGestureContainer addGestureRecognizer:swipe];
[self.bannerSwipeGestureContainer addGestureRecognizer:centerTap];
[self.bannerLeftTapGestureContainer addGestureRecognizer:leftTap];
[self.bannerRightTapGestureContainer addGestureRecognizer:rightTap];
}
- (void)handleSwipe {
[[NSNotificationCenter defaultCenter] postNotificationName:@"SwipeOutBanner" object:nil];
}
- (void)handleBannerTap:(UITapGestureRecognizer *)tapGesture {
CGPoint tapPoint = [tapGesture locationInView:self.bannerContainer];
// 检查当前显示的 banner 是否在 tap 位置可以响应事件
if ([self isPointInBannerInteractiveArea:tapPoint]) {
// banner 可以响应,不处理,让 banner 继续原有逻辑
NSLog(@"🎯 Banner tap 位置在可交互区域banner 将处理此事件");
[[NSNotificationCenter defaultCenter] postNotificationName:@"TapBanner"
object:nil
userInfo:@{@"point": [NSValue valueWithCGPoint:tapPoint]}];
} else {
// banner 不能响应,保存 tap 位置
self.savedTapPoint = tapPoint;
self.hasSavedTapPoint = YES;
NSLog(@"💾 Banner tap 位置不在可交互区域,已保存位置: %@", NSStringFromCGPoint(tapPoint));
// 将 bannerContainer 中的点转换为屏幕坐标系
CGPoint screenPoint = [self.bannerContainer convertPoint:tapPoint toView:nil];
// UIView *tappedView = tapGesture.view;
[[NSNotificationCenter defaultCenter] postNotificationName:@"BannerTapToFunctionContainer"
object:nil
userInfo:@{@"point": [NSValue valueWithCGPoint:screenPoint]}];
}
}
- (BOOL)isPointInBannerInteractiveArea:(CGPoint)point {
// 检查当前显示的 banner 是否在指定位置可以响应事件
for (UIView *subview in self.bannerContainer.subviews) {
if (subview.hidden || subview.alpha <= 0.01) {
continue;
}
// 检查点是否在子视图范围内
if (CGRectContainsPoint(subview.bounds, point)) {
// 检查子视图是否支持用户交互
if (subview.userInteractionEnabled) {
// 进一步检查子视图是否有可点击的元素
CGPoint subviewPoint = [subview convertPoint:point fromView:self.bannerContainer];
UIView *hitView = [subview hitTest:subviewPoint withEvent:nil];
if (hitView && hitView.userInteractionEnabled) {
return YES;
}
}
}
}
return NO;
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
// 允许手势同时识别
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
CGPoint touchPoint = [touch locationInView:self.bannerContainer];
CGFloat containerWidth = self.bannerContainer.bounds.size.width;
// 计算区域边界
CGFloat leftBoundary = containerWidth / 6.0; // 1/6 宽度
CGFloat rightBoundary = containerWidth * 5.0 / 6.0; // 5/6 宽度
if ([gestureRecognizer isKindOfClass:[UISwipeGestureRecognizer class]]) {
// Swipe 手势只在中央 2/3 区域生效
return touchPoint.x >= leftBoundary && touchPoint.x <= rightBoundary;
} else if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
// Tap 手势只在左右两侧 1/6 区域生效
// return touchPoint.x < leftBoundary || touchPoint.x > rightBoundary;
// 根据手势所在的容器来决定区域
if (gestureRecognizer.view == self.bannerSwipeGestureContainer) {
// 中央区域的 tap 手势
return touchPoint.x >= leftBoundary && touchPoint.x <= rightBoundary;
} else {
// 左右两侧的 tap 手势
return touchPoint.x < leftBoundary || touchPoint.x > rightBoundary;
}
}
return YES;
}
#pragma mark - Animations
- (void)enterRoomAnimationFor:(UIView *)targetView
startFrom:(CGPoint)sfPoint
startTo:(CGPoint)stPoint
endFrom:(CGPoint)efPoint
endTo:(CGPoint)etPoint
duration:(CFTimeInterval)duration
completion:(void (^)(BOOL finished))completion {
@kWeakify(self);
[self enterRoomMoveInAnimationFor:targetView
fromValue:sfPoint
toValue:stPoint
completion:^(BOOL finished) {
if (finished) {
@kStrongify(self);
@kWeakify(self);
[self enterRoomMoveOutAnimationFor:targetView
fromValue:efPoint
toValue:etPoint
beginTime:duration
completion:^(BOOL finished) {
if (finished) {
@kStrongify(self);
[self cleanupAnimationsForView:targetView];
if (completion) {
completion(finished);
}
}
}];
}
}];
}
- (void)enterRoomMoveInAnimationFor:(UIView *)view
fromValue:(CGPoint)fromValue
toValue:(CGPoint)toValue
completion:(void (^)(BOOL finished))completion {
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
springAnimation.springSpeed = 12;
springAnimation.springBounciness = 10.f;
springAnimation.fromValue = [NSValue valueWithCGPoint:fromValue];
springAnimation.toValue = [NSValue valueWithCGPoint:toValue];
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
if (completion) completion(finished);
}];
[view pop_addAnimation:springAnimation forKey:@"amationSpringIn"];
}
- (void)enterRoomMoveOutAnimationFor:(UIView *)view
fromValue:(CGPoint)fromValue
toValue:(CGPoint)toValue
beginTime:(CFTimeInterval)beginTime
completion:(void (^)(BOOL finished))completion {
POPSpringAnimation *moveAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
moveAnimation.fromValue = [NSValue valueWithCGPoint:fromValue];
moveAnimation.toValue = [NSValue valueWithCGPoint:toValue];
moveAnimation.beginTime = beginTime;
moveAnimation.springSpeed = 8;
moveAnimation.springBounciness = 15.f;
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
if (completion) completion(finished);
}];
[view pop_addAnimation:moveAnimation forKey:@"animetionMoveOut"];
}
- (void)cleanupAnimationsForView:(UIView *)view {
[view pop_removeAllAnimations];
[view removeFromSuperview];
}
#pragma mark - Common methods
- (NSString *)_resolveUserNameFromContent:(NIMChatroomNotificationContent *)content
extModel:(XPMessageRemoteExtModel *)extModel {
// 1) extModel.nick 优先
if (![NSString isEmpty:extModel.nick]) {
return extModel.nick;
}
// 2) 如果 extModel.nick 为空,看 content.source.nick
if (![NSString isEmpty:content.source.nick]) {
return content.source.nick;
}
// 3) 如果依然空,并且是自己,则取本地 nick
if (content.source.userId.intValue == self.hostDelegate.getUserInfo.uid &&
![NSString isEmpty:self.hostDelegate.getUserInfo.nick]) {
return self.hostDelegate.getUserInfo.nick;
}
// 4) 兜底
return @"";
}
- (NSString *)_mapExperLevelSeqToLocalKey:(NSInteger)seq {
if (seq >= 30 && seq <= 39) {
return @"experience_entre_effect_30";
} else if (seq >= 40 && seq <= 49) {
return @"experience_entre_effect_40";
} else if (seq >= 50 && seq <= 59) {
return @"experience_entre_effect_50";
} else if (seq >= 60 && seq <= 69) {
return @"experience_entre_effect_60";
} else if (seq >= 70 && seq <= 79) {
return @"experience_entre_effect_70";
} else if (seq >= 80 && seq <= 89) {
return @"experience_entre_effect_80";
} else if (seq >= 90) {
return @"experience_entre_effect_90";
}
return @"";
}
- (BOOL)_isInSudGame {
BOOL isGamePlaying = NO;
if (self.hostDelegate.getRoomInfo.type == RoomType_MiniGame) {
NSInteger micCount = self.hostDelegate.getRoomInfo.mgMicNum;
for (int i = -1; i<micCount; i++) {
NSMutableDictionary * micQueue = self.hostDelegate.getMicroQueue;
MicroQueueModel *micSequence = [micQueue objectForKey:[NSString stringWithFormat:@"%d", i]];
if (micSequence == nil || micSequence.userInfo == nil) {
continue;
}
if (micSequence.userInfo.uid == [AccountInfoStorage instance].getUid.integerValue &&
micSequence.userInfo.gameStatus == LittleGamePlayStatus_Plying) {
isGamePlaying = YES;
break;
}
}
}
return isGamePlaying;
}
- (void)_addSubviewToMiddleContainer:(UIView *)view {
if (view.superview == nil) {
[self.middleContainer addSubview:view];
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.mas_equalTo(self.middleContainer);
make.width.mas_equalTo(KScreenWidth);
make.height.mas_equalTo(KScreenHeight);
}];
}
view.hidden = NO;
}
#pragma mark - Lazy init
- (XPRoomAnimationHitView *)bottomContainer {
if (!_bottomContainer) {
_bottomContainer = [[XPRoomAnimationHitView alloc] init];
}
return _bottomContainer;
}
- (XPRoomAnimationHitView *)middleContainer {
if (!_middleContainer) {
_middleContainer = [[XPRoomAnimationHitView alloc] init];
}
return _middleContainer;
}
- (XPRoomAnimationHitView *)topContainer {
if (!_topContainer) {
_topContainer = [[XPRoomAnimationHitView alloc] init];
}
return _topContainer;
}
- (XPRoomAnimationHitView *)bannerContainer {
if (!_bannerContainer) {
_bannerContainer = [[XPRoomAnimationHitView alloc] init];
#if DEBUG
_bannerContainer.backgroundColor = [UIColor colorWithWhite:0.8 alpha:0.4];
#endif
}
return _bannerContainer;
}
- (UIView *)bannerSwipeGestureContainer {
if (!_bannerSwipeGestureContainer) {
_bannerSwipeGestureContainer = [[UIView alloc] init];
_bannerSwipeGestureContainer.userInteractionEnabled = YES;
#if DEBUG
_bannerSwipeGestureContainer.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.4];
#endif
}
return _bannerSwipeGestureContainer;
}
- (UIView *)bannerLeftTapGestureContainer {
if (!_bannerLeftTapGestureContainer) {
_bannerLeftTapGestureContainer = [[UIView alloc] init];
_bannerLeftTapGestureContainer.userInteractionEnabled = YES;
#if DEBUG
_bannerLeftTapGestureContainer.backgroundColor = [UIColor colorWithRed:0 green:1 blue:0 alpha:0.4];
#endif
}
return _bannerLeftTapGestureContainer;
}
- (UIView *)bannerRightTapGestureContainer {
if (!_bannerRightTapGestureContainer) {
_bannerRightTapGestureContainer = [[UIView alloc] init];
_bannerRightTapGestureContainer.userInteractionEnabled = YES;
#if DEBUG
_bannerRightTapGestureContainer.backgroundColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.4];
#endif
}
return _bannerRightTapGestureContainer;
}
- (SVGAImageView *)enterEffectView {
if (_enterEffectView == nil) {
_enterEffectView = [[SVGAImageView alloc]init];
_enterEffectView.delegate = self;
_enterEffectView.contentMode = UIViewContentModeScaleAspectFill;
_enterEffectView.frame = CGRectMake(0, 0, KScreenWidth, 50);
_enterEffectView.backgroundColor = [UIColor clearColor];
_enterEffectView.alpha = 0;
_enterEffectView.userInteractionEnabled = NO;
}
return _enterEffectView;
}
- (NSMutableArray *)svgaQueue{
if(!_svgaQueue){
_svgaQueue = [NSMutableArray array];
}
return _svgaQueue;
}
- (void)addToSvgaQueue:(GiftReceiveInfoModel *)model {
dispatch_async(self.giftEffectsQueue, ^{
[self.svgaQueue addObject:model];
});
}
- (void)removeFromSvgaQueueAtIndex:(NSInteger)index {
dispatch_async(self.giftEffectsQueue, ^{
if (index < self.svgaQueue.count) {
if (index < self.svgaQueue.count) {
[self.svgaQueue xpSafeRemoveObjectAtIndex:index];
}
}
});
}
- (XPRoomGiftAnimationParser *)vapParser {
if (!_vapParser) {
_vapParser = [[XPRoomGiftAnimationParser alloc] init];
}
return _vapParser;
}
- (PAGView *)pagGiftEffectView{
if(!_pagGiftEffectView){
_pagGiftEffectView = [[PAGView alloc]init];
[_pagGiftEffectView addListener:self];
_pagGiftEffectView.backgroundColor = [UIColor clearColor];
_pagGiftEffectView.userInteractionEnabled = NO;
_pagGiftEffectView.repeatCount = 1;
_pagGiftEffectView.scaleMode = PAGScaleModeStretch;
}
return _pagGiftEffectView;
}
- (VAPView *)vapGiftEffectView {
if (!_vapGiftEffectView) {
_vapGiftEffectView = [[VAPView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
_vapGiftEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
_vapGiftEffectView.contentMode = UIViewContentModeScaleAspectFill;
_vapGiftEffectView.hidden = YES;
_vapGiftEffectView.userInteractionEnabled = NO;
}
return _vapGiftEffectView;
}
- (SVGAParser *)vggParser {
if (!_vggParser) {
_vggParser = [[SVGAParser alloc] init];
}
return _vggParser;
}
- (SVGAImageView *)vggGiftEffectView {
if (!_vggGiftEffectView) {
_vggGiftEffectView = [[SVGAImageView alloc]init];
_vggGiftEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
_vggGiftEffectView.userInteractionEnabled = NO;
_vggGiftEffectView.delegate = self;
_vggGiftEffectView.hidden = YES;
_vggGiftEffectView.loops = 1;
_vggGiftEffectView.clearsAfterStop = YES;
}
return _vggGiftEffectView;
}
- (VAPView *)carVapEffectView {
if (!_carVapEffectView) {
_carVapEffectView = [[VAPView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
_carVapEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];
_carVapEffectView.contentMode = UIViewContentModeScaleAspectFill;
_carVapEffectView.hidden = YES;
}
return _carVapEffectView;
}
- (SVGAImageView *)carSVGAEffectView {
if (_carSVGAEffectView == nil) {
_carSVGAEffectView = [[SVGAImageView alloc]init];
_carSVGAEffectView.delegate = self;
_carSVGAEffectView.contentMode = UIViewContentModeScaleAspectFit;
_carSVGAEffectView.frame = CGRectMake(0, 0, KScreenWidth, KScreenHeight);
_carSVGAEffectView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
_carSVGAEffectView.hidden = YES;
_carSVGAEffectView.userInteractionEnabled = NO;
_carSVGAEffectView.loops = 1;
_carSVGAEffectView.clearsAfterStop = YES;
}
return _carSVGAEffectView;
}
- (PAGView *)carPagEffectView{
if(!_carPagEffectView){
_carPagEffectView = [[PAGView alloc]init];
[_carPagEffectView addListener:self];
_carPagEffectView.backgroundColor = [UIColor clearColor];
_carPagEffectView.userInteractionEnabled = NO;
_carPagEffectView.repeatCount = 1;
_carPagEffectView.scaleMode = PAGScaleModeStretch;
}
return _carPagEffectView;
}
#pragma mark - OLD METHODs
- (void)receiveLuckyGiftBigPrize:(AttachmentModel *)attachment {
if ([self _isInSudGame]) {return;}
PIBaseAnimationViewModel * prizeModel = [PIBaseAnimationViewModel modelWithDictionary:attachment.data];
prizeModel.type = GiftBannerType_Lucky;
prizeModel.isInRoomVisable = attachment.second == Custom_Message_Sub_Room_Gift_LuckBag;
if(self.animationListB.count == 0 && self.isPlayOfB == NO){
[self createBigPrizeAnimation:prizeModel];
}
[self.animationListB addObject:prizeModel];
}
- (void)createBigPrizeAnimation:(PIBaseAnimationViewModel *)prizeModel {
self.isPlayOfB = YES;
CGFloat top = (kNavigationHeight + 15);
XPRoomLuckyBigPrizeView * luckyGiftEffectView = [[XPRoomLuckyBigPrizeView alloc] initWithFrame:CGRectMake(KScreenWidth, top, 375, 71)];
luckyGiftEffectView.delegate = self;
[self.topContainer addSubview:luckyGiftEffectView];
luckyGiftEffectView.giftInfo = prizeModel;
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
springAnimation.springSpeed = 12;
springAnimation.springBounciness = 10.f;
springAnimation.fromValue = [NSValue valueWithCGPoint:luckyGiftEffectView.center];
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(KScreenWidth / 2, luckyGiftEffectView.center.y)];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 7 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, luckyGiftEffectView.center.y)];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, luckyGiftEffectView.center.y)];
moveAnimation.beginTime = CACurrentMediaTime();
moveAnimation.duration = 0.5;
moveAnimation.repeatCount = 1;
moveAnimation.removedOnCompletion = YES;
@kWeakify(self);
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
@kStrongify(self);
if (finished) {
[luckyGiftEffectView removeFromSuperview];
if (self.animationListB.count > 0) {
[self.animationListB xpSafeRemoveObjectAtIndex:0];
}
self.isPlayOfB = NO;
[self playAnimationWithModel];
}
}];
[luckyGiftEffectView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
});
[luckyGiftEffectView pop_addAnimation:springAnimation forKey:@"nobleLevelUpspingOutAnimation"];
}
- (void)receiveCandyTreeGiftHighLevle:(AttachmentModel *)attatchment {
if ([self _isInSudGame]) {return;}
PIBaseAnimationViewModel *giftModel = [PIBaseAnimationViewModel new];
giftModel.data = attatchment.data;
giftModel.second = attatchment.second;
giftModel.first = attatchment.first;
giftModel.type = GiftBannerType_Love;
if (self.animationListB.count == 0 && self.isPlayOfB == NO) {
[self createCandyTreeBannerAnimation:giftModel];
}
[self.animationListB addObject:giftModel];
}
- (void)createCandyTreeBannerAnimation:(PIBaseAnimationViewModel *)attatchment {
CGFloat kscale = (CGFloat)60 / (CGFloat)375;
self.isPlayOfB = YES;
CGFloat top = (kNavigationHeight + 15);
XPRoomCandyGiftView *candyTreeView = [[XPRoomCandyGiftView alloc] initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth , KScreenWidth * kscale)];
candyTreeView.isMaxLargeGift = attatchment.second == Custom_Message_Sub_Look_Love_InRoom_NeedAllMicSend;
candyTreeView.candyInfo = attatchment.data;
[self.middleContainer addSubview:candyTreeView];
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
springAnimation.springSpeed = 12;
springAnimation.springBounciness = 10.f;
springAnimation.fromValue = [NSValue valueWithCGPoint:candyTreeView.center];
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(candyTreeView.frame.size.width / 2, candyTreeView.center.y)];
@kWeakify(self);
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
@kStrongify(self);
if (finished) {
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, candyTreeView.center.y)];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, candyTreeView.center.y)];
moveAnimation.beginTime = CACurrentMediaTime() + 3;
moveAnimation.duration = 0.5;
moveAnimation.repeatCount = 1;
moveAnimation.removedOnCompletion = YES;
@kWeakify(self);
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
@kStrongify(self);
if (finished) {
[candyTreeView removeFromSuperview];
self.isPlayOfB = NO;
if (self.animationListB.count > 0) {
[self.animationListB xpSafeRemoveObjectAtIndex:0];
}
[self playAnimationWithModel];
}
}];
[candyTreeView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
}
}];
[candyTreeView pop_addAnimation:springAnimation forKey:@"candyTreespingOutAnimation"];
}
- (void)receiveNobleLevelUp:(AttachmentModel *)attachment {
@kWeakify(self);
[[NetImageView new]loadImageWithUrl:attachment.data[@"avatar"] completion:^(UIImage * _Nonnull image, NSURL * _Nonnull url) {
@kStrongify(self);
PIBaseAnimationViewModel *nobleModel = [PIBaseAnimationViewModel new];
nobleModel.data = attachment.data;
nobleModel.type = GiftBannerType_Nobleman;
if (self.animationListB.count == 0 && self.isPlayOfB == NO) {
[self createNobleLevelUpBannerAnimation:nobleModel];
}
[self.animationListB addObject:nobleModel];
}];
}
- (void)createNobleLevelUpBannerAnimation:(PIBaseAnimationViewModel *)model {
self.isPlayOfB = YES;
CGFloat top = (kNavigationHeight + 15);
XPRoomNobleLevelUpView *nobleLevelUpView = [[XPRoomNobleLevelUpView alloc] initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth, 90)];
nobleLevelUpView.nobleInfo = model.data;
[self.topContainer addSubview:nobleLevelUpView];
@kWeakify(self);
@kWeakify(nobleLevelUpView);
nobleLevelUpView.completionBlock = ^{
@kStrongify(self);
@kStrongify(nobleLevelUpView);
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
springAnimation.springSpeed = 12;
springAnimation.springBounciness = 10.f;
springAnimation.fromValue = [NSValue valueWithCGPoint:nobleLevelUpView.center];
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(nobleLevelUpView.frame.size.width / 2, nobleLevelUpView.center.y)];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, nobleLevelUpView.center.y)];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, nobleLevelUpView.center.y)];
moveAnimation.beginTime = CACurrentMediaTime() + 3;
moveAnimation.duration = 0.5;
moveAnimation.repeatCount = 1;
moveAnimation.removedOnCompletion = YES;
@kWeakify(self);
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
@kStrongify(self);
if (finished) {
self.isPlayOfB = NO;
[nobleLevelUpView removeFromSuperview];
if (self.animationListB.count > 0) {
[self.animationListB xpSafeRemoveObjectAtIndex:0];
}
[self playAnimationWithModel];
}
}];
[nobleLevelUpView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
});
[nobleLevelUpView pop_addAnimation:springAnimation forKey:@"nobleLevelUpspingOutAnimation"];
};
}
- (void)createAnchorHourRankAnimation:(PIBaseAnimationViewModel *)attachment {
self.isPlayOfB = YES;
CGFloat top = (kNavigationHeight + 15);
XPRoomAnchorRankBannerView *anchorRankView = [[XPRoomAnchorRankBannerView alloc] initWithFrame:CGRectMake(KScreenWidth,top, KScreenWidth, kGetScaleWidth(55))];
anchorRankView.anchorRankInfo = [RoomHalfHourRankModel modelWithDictionary:attachment.data];
anchorRankView.delegate = self;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gotoTopRankAnchorRoom:)];
[anchorRankView addGestureRecognizer:tap];
[self.topContainer addSubview:anchorRankView];
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
springAnimation.springSpeed = 12;
springAnimation.springBounciness = 10.f;
springAnimation.fromValue = [NSValue valueWithCGPoint:anchorRankView.center];
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(anchorRankView.frame.size.width / 2, anchorRankView.center.y)];
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
if (finished) {
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, anchorRankView.center.y)];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, anchorRankView.center.y)];
moveAnimation.beginTime = CACurrentMediaTime() + 3;
moveAnimation.duration = 0.5;
moveAnimation.repeatCount = 1;
moveAnimation.removedOnCompletion = YES;
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
[anchorRankView removeFromSuperview];
self.isPlayOfB = NO;
if(self.animationListB.count > 0){
[self.animationListB xpSafeRemoveObjectAtIndex:0];
[self playAnimationWithModel];
}
}];
[anchorRankView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
}
}];
[anchorRankView pop_addAnimation:springAnimation forKey:@"nobleLevelUpspingOutAnimation"];
}
- (void)gotoTopRankAnchorRoom:(UITapGestureRecognizer *)tap {
XPRoomAnchorRankBannerView * view = (XPRoomAnchorRankBannerView *)tap.view;
if (view.anchorRankInfo.uid.integerValue > 0) {
[self.hostDelegate exitRoom];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:view.anchorRankInfo.uid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
});
}
}
- (void)receiveTreasureFairyGiftHighLevel:(AttachmentModel *)attatchment {
if ([self _isInSudGame]) {return;}
PIBaseAnimationViewModel *giftModel = [PIBaseAnimationViewModel new];
giftModel.data = attatchment.data;
giftModel.second = attatchment.second;
giftModel.first = attatchment.first;
giftModel.type = GiftBannerType_Fairy;
if (self.animationListB.count == 0 && self.isPlayOfB == NO) {
[self createTreasureFairyBannerAnimation:giftModel];
}
[self.animationListB addObject:giftModel];
}
- (void)createTreasureFairyBannerAnimation:(PIBaseAnimationViewModel *)attatchment {
self.isPlayOfB = YES;
CGFloat kscale = (CGFloat)60 / (CGFloat)375;
CGFloat top = (kNavigationHeight + 15);
XPTreasureFairyGiftView *treasureView = [[XPTreasureFairyGiftView alloc] initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth , KScreenWidth * kscale)];
//最大礼物
if ((attatchment.second == Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L5) || (attatchment.second == Custom_Message_Sub_Treasure_Fairy_Convert_L3)) {
treasureView.isMaxLargeGift = YES;
}else{
treasureView.isMaxLargeGift = NO;
}
if ((attatchment.second == Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L4) || (attatchment.second == Custom_Message_Sub_Treasure_Fairy_Draw_Gift_L5)) {
treasureView.isDrawGift = YES; //抽奖
}else{
treasureView.isDrawGift = NO; //召唤
}
treasureView.treasureInfo = attatchment.data;
[self.middleContainer addSubview:treasureView];
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
springAnimation.springSpeed = 12;
springAnimation.springBounciness = 10.f;
springAnimation.fromValue = [NSValue valueWithCGPoint:treasureView.center];
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(treasureView.frame.size.width / 2, treasureView.center.y)];
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
if (finished) {
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, treasureView.center.y)];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, treasureView.center.y)];
moveAnimation.beginTime = CACurrentMediaTime() + 3;
moveAnimation.duration = 0.5;
moveAnimation.repeatCount = 1;
moveAnimation.removedOnCompletion = YES;
@kWeakify(self);
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
@kStrongify(self);
if (finished) {
[treasureView removeFromSuperview];
self.isPlayOfB = NO;
if (self.animationListB.count > 0) {
[self.animationListB xpSafeRemoveObjectAtIndex:0];
}
[self playAnimationWithModel];
}
}];
[treasureView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
}
}];
[treasureView pop_addAnimation:springAnimation forKey:@"candyTreespingOutAnimation"];
}
- (void)createGiftCompoundBannerAnimation:(PIBaseAnimationViewModel *)attachment {
self.isPlayOfB = YES;
XPRoomGiftCompoundView *compoundGiftView = [[XPRoomGiftCompoundView alloc] initWithFrame:CGRectMake(KScreenWidth, kNavigationHeight + 15, KScreenWidth, 45)];
compoundGiftView.compoundGiftInfo = attachment.data;
[self.middleContainer addSubview:compoundGiftView];
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
springAnimation.springSpeed = 12;
springAnimation.springBounciness = 10.f;
springAnimation.fromValue = [NSValue valueWithCGPoint:compoundGiftView.center];
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(compoundGiftView.frame.size.width / 2, compoundGiftView.center.y)];
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
if (finished) {
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, compoundGiftView.center.y)];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, compoundGiftView.center.y)];
moveAnimation.beginTime = CACurrentMediaTime() + 3;
moveAnimation.duration = 0.5;
moveAnimation.repeatCount = 1;
moveAnimation.removedOnCompletion = YES;
@kWeakify(self);
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
@kStrongify(self);
if (finished) {
[compoundGiftView removeFromSuperview];
self.isPlayOfB = NO;
if(self.animationListB.count > 0){
[self.animationListB xpSafeRemoveObjectAtIndex:0];
}
[self playAnimationWithModel];
}
}];
[compoundGiftView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
}
}];
[compoundGiftView pop_addAnimation:springAnimation forKey:@"compoundGiftSpingOutAnimation"];
}
- (void)createGeneralFloatingScreenAnimation:(PIBaseAnimationViewModel *)attachment bannerModel:(PIUniversalBannerModel *)model {
self.isPlayOfB = YES;
CGFloat top = (kNavigationHeight + 15);
if (!model) {
model = [PIUniversalBannerModel modelWithDictionary:attachment.data];
}
BOOL isSvga = [model.resourceType.uppercaseString isEqualToString:@"SVGA"];
__block PIUniversalBannerView *bannerView;
@kWeakify(self);
if (isSvga == YES) {
SVGAParser *parser = [SVGAParser new];
[parser parseWithURL:[NSURL URLWithString:model.resourceContent] completionBlock:^(SVGAVideoEntity * _Nonnull videoItem) {
@kStrongify(self);
model.videoItem = videoItem;
CGFloat height = kGetScaleWidth(60);
if(videoItem.videoSize.width > 0){
height = KScreenWidth * videoItem.videoSize.height / videoItem.videoSize.width;
}
bannerView = [[PIUniversalBannerView alloc]initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth, height)];
[self showGeneralFloatingScreenView:bannerView model:model];
} failureBlock:^(NSError * _Nonnull error) {
@kStrongify(self);
[bannerView removeFromSuperview];
self.isPlayOfB = NO;
if(self.animationListB.count > 0){
[self.animationListB xpSafeRemoveObjectAtIndex:0];
}
[self playAnimationWithModel];
}];
}else{
if (!_imageLoader) {
_imageLoader = [[NetImageView alloc] init];
}
[self.imageLoader loadImageWithUrl:model.resourceContent
completion:^(UIImage * _Nonnull image, NSURL * _Nonnull url) {
@kStrongify(self);
model.image = image;
CGFloat width = image.size.width <= 0 ? kGetScaleWidth(60) : image.size.width;
CGFloat height = image.size.height ;
CGFloat getHeight = KScreenWidth * height / width;
if (getHeight > 100) {
getHeight = 100;
}
bannerView = [[PIUniversalBannerView alloc]initWithFrame:CGRectMake(KScreenWidth, top, KScreenWidth, getHeight) ];
[self showGeneralFloatingScreenView:bannerView model:model];
}
fail:^(NSError * _Nonnull error) {
@kStrongify(self);
[bannerView removeFromSuperview];
self.isPlayOfB = NO;
if(self.animationListB.count > 0){
[self.animationListB xpSafeRemoveObjectAtIndex:0];
}
[self playAnimationWithModel];
}];
}
}
-(void)showGeneralFloatingScreenView:(PIUniversalBannerView *)bannerView model:(PIUniversalBannerModel *)model{
BOOL isSvga = [model.resourceType isEqualToString:@"SVGA"];
bannerView.isSvga = isSvga;
bannerView.delegate = self;
if (!_universalBannerViewCaches) {
_universalBannerViewCaches = @[].mutableCopy;
}
[self.universalBannerViewCaches addObject:bannerView];
@kWeakify(bannerView);
@kWeakify(self);
[bannerView setAllowToPlay:^{
@kStrongify(self);
@kStrongify(bannerView);
[self.topContainer addSubview:bannerView];
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
springAnimation.springSpeed = 12;
springAnimation.springBounciness = 10.f;
springAnimation.fromValue = [NSValue valueWithCGPoint:bannerView.center];
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(bannerView.frame.size.width / 2, bannerView.center.y)];
@kWeakify(self);
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
if (finished) {
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, bannerView.center.y)];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, bannerView.center.y)];
moveAnimation.beginTime = CACurrentMediaTime() + 5;
moveAnimation.duration = 0.5;
moveAnimation.repeatCount = 1;
moveAnimation.removedOnCompletion = YES;
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
@kStrongify(self);
if (finished) {
[bannerView removeFromSuperview];
[self.universalBannerViewCaches removeObject:bannerView];
self.isPlayOfB = NO;
if(self.animationListB.count > 0){
[self.animationListB xpSafeRemoveObjectAtIndex:0];
}
[self playAnimationWithModel];
}
}];
[bannerView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
}
}];
[bannerView pop_addAnimation:springAnimation forKey:@"starKitchenOutAnimation"];
}];
bannerView.model = model;
}
- (void)roomDatingPublicResult:(AttachmentModel *)attachment {
self.datingEffectQueue = [NSMutableArray array];
///心动结果公布的话 结果是一个数组
NSArray * results = [DatingInfoModel modelsWithArray:attachment.data[@"list"]];
[self.datingEffectQueue addObjectsFromArray:results];
if (self.datingEffectQueue.count > 0) {
[self startDatingAnimation:self.datingEffectQueue.firstObject];
}
}
- (void)startDatingAnimation:(DatingInfoModel *)datingModel {
[[NSNotificationCenter defaultCenter] postNotificationName:@"message" object:[self createRoomDatingResultMessage:datingModel]];
NSString * targetUid= [NSString stringWithFormat:@"%ld", datingModel.targetUid];
NSString * uid= [NSString stringWithFormat:@"%ld", datingModel.uid];
if (datingModel.hasHeart || datingModel.hasSelectUser) {
datingModel.originPoint = [self.hostDelegate animationPointAtStageViewByUid:uid];
datingModel.targetPoint = [self.hostDelegate animationPointAtStageViewByUid:targetUid];
}
XPRoomDatingAnimationView *datingView = [[XPRoomDatingAnimationView alloc] init];
[self.topContainer addSubview:datingView];
[datingView startAnimationWithModel:datingModel finishBlock:^(BOOL finish) {
[datingView removeFromSuperview];
[self.datingEffectQueue removeObject:datingModel];
if (self.datingEffectQueue.count > 0) {
DatingInfoModel * datingModel = [self.datingEffectQueue firstObject];
[self startDatingAnimation:datingModel];
}
}];
}
- (NIMMessage *)createRoomDatingResultMessage:(DatingInfoModel *)datingModel {
NIMMessage * message = [[NIMMessage alloc] init];
NIMSession * session = [NIMSession session:[NSString stringWithFormat:@"%ld", self.hostDelegate.getRoomInfo.roomId] type:NIMSessionTypeChatroom];
[message setValue:session forKey:@"session"];
AttachmentModel * attach = [[AttachmentModel alloc] init];
attach.first = CustomMessageType_RoomPlay_Dating;
if (datingModel.hasHeart) {///如果是互选的话
attach.second = Custom_Message_Sub_Room_Play_Dating_Result_Mutual;
} else {
attach.second = Custom_Message_Sub_Room_Play_Dating_Result_Not_Mutual;
}
attach.data = [datingModel model2dictionary];
NIMCustomObject * object = [[NIMCustomObject alloc] init];
object.attachment = attach;
message.messageObject = object;
return message;
}
- (void)acrossRoomPKBannerAnimation:(AttachmentModel *)attacment {
AcrossRoomPKPrizeModel * prizeModel = [AcrossRoomPKPrizeModel modelWithJSON:attacment.data];
if (attacment.second == Custom_Message_Sub_AnchorPK_Result) {
prizeModel.pkType = 1;
} else {
prizeModel.pkType = 0;
}
[self.acrossRoomPKQueue addObject:prizeModel];
if (self.acrossRoomPKQueue.count == 1 ) {//判断为1个时开始播放防止多条消息回来后重叠播放
[self startAcrossRoomPKAnimation:self.acrossRoomPKQueue.firstObject];
}
}
- (void)startAcrossRoomPKAnimation:(AcrossRoomPKPrizeModel *)model {
XPAcrossRoomPKPrizeView *wishEffectView = [[XPAcrossRoomPKPrizeView alloc] initWithFrame:CGRectMake(KScreenWidth, kNavigationHeight+40, KScreenWidth, 87)];
wishEffectView.data = model;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gotoPkWinRoom:)];
[wishEffectView addGestureRecognizer:tap];
[self.topContainer addSubview:wishEffectView];
[UIView animateWithDuration:0.5 animations:^{
wishEffectView.frame = CGRectMake(0, kNavigationHeight+40, KScreenWidth, 87);
} completion:^(BOOL finished) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.5 animations:^{
wishEffectView.hidden = YES;
} completion:^(BOOL finished) {
[wishEffectView removeFromSuperview];
[self.acrossRoomPKQueue removeObject:model];
if (self.acrossRoomPKQueue.count > 0) {
[self startAcrossRoomPKAnimation:self.acrossRoomPKQueue.firstObject];
}
}];
});
}];
}
- (void)gotoPkWinRoom:(UITapGestureRecognizer *)tap {
XPAcrossRoomPKPrizeView * view = (XPAcrossRoomPKPrizeView *)tap.view;
if (view.data.winUid.length > 0) {
[self.hostDelegate exitRoom];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:view.data.winUid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
});
}
}
- (void)receiveFansTeamGiftHandleSendGiftAnimation:(AttachmentModel *)attachment {
if ([self _isInSudGame]) {return;}
if (!self.hostDelegate.getRoomInfo.hasAnimationEffect) {return;}
GiftReceiveInfoModel *receiveInfo = [[GiftReceiveInfoModel alloc] init];
GiftInfoModel *gift = [GiftInfoModel modelWithJSON:attachment.data[@"giftVo"]];
receiveInfo.gift = gift;
receiveInfo.giftInfo = gift;
receiveInfo.targetUid = [NSString stringWithFormat:@"%ld", self.hostDelegate.getRoomInfo.uid];
GiftInfoModel * giftInfo = receiveInfo.gift ? receiveInfo.gift : receiveInfo.giftInfo;
if (attachment.second == Custom_Message_Sub_AllMicroLuckySend || attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend || attachment.second == Custom_Message_Sub_Gift_LuckySend) {
NSString * giftId = [NSString stringWithFormat:@"%ld", receiveInfo.luckyGiftList.giftList.firstObject.giftId];
giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:giftId inRoom:@(receiveInfo.roomUid).stringValue];
}
if (giftInfo == nil) {
giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:receiveInfo.giftId inRoom:@(receiveInfo.roomUid).stringValue];
}
///在最外面判断是否可以拿到那个礼物 后面使用就不用判断了
receiveInfo.gift = giftInfo;
receiveInfo.isLuckyBagGift = (attachment.second == Custom_Message_Sub_AllMicroLuckySend || attachment.second == Custom_Message_Sub_AllBatchMicroLuckySend || attachment.second == Custom_Message_Sub_Gift_LuckySend);
[self.giftAnimationManager enqueueGift:receiveInfo];
}
- (void)receiveAnchorHourRank:(AttachmentModel *)attachment {
PIBaseAnimationViewModel *anchorModel =[PIBaseAnimationViewModel new];
anchorModel.data = attachment.data;
anchorModel.type = GiftBannerType_AnchorHour;
if(self.animationListB.count == 0 && self.isPlayOfB == NO){
[self createAnchorHourRankAnimation:anchorModel];
}
[self.animationListB addObject:anchorModel];
}
- (void)receiveGiftCompound:(AttachmentModel *)attachment {
if ([self _isInSudGame]) {return;}
PIBaseAnimationViewModel *magicModel =[PIBaseAnimationViewModel new];
magicModel.data = attachment.data;
magicModel.type = GiftBannerType_Magic_House;
if(self.animationListB.count == 0 && self.isPlayOfB == NO){
[self createGiftCompoundBannerAnimation:magicModel];
}
[self.animationListB addObject:magicModel];
}
- (void)receiveRoomSailing:(AttachmentModel *)attachment {
if ([self _isInSudGame]) {return;}
if (self.sailingQueue.count == 0) {
[self createSailingBannerAnimation:attachment];
}
[self.sailingQueue addObject:attachment];
}
- (void)createSailingBannerAnimation:(AttachmentModel *)attatchment {
CGFloat kscale = (CGFloat)60 / (CGFloat)375;
XPSailingAnimationView *sailingView = [[XPSailingAnimationView alloc] initWithFrame:CGRectMake(KScreenWidth, kNavigationHeight + 15, KScreenWidth, KScreenWidth * kscale)];
sailingView.prizeInfo = attatchment.data;
[self.middleContainer addSubview:sailingView];
POPSpringAnimation *springAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPViewCenter];
springAnimation.springSpeed = 12;
springAnimation.springBounciness = 10.f;
springAnimation.fromValue = [NSValue valueWithCGPoint:sailingView.center];
springAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(sailingView.frame.size.width / 2, sailingView.center.y)];
[springAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
if (finished) {
POPBasicAnimation *moveAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPViewCenter];
moveAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, sailingView.center.y)];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(-KScreenWidth/2, sailingView.center.y)];
moveAnimation.beginTime = CACurrentMediaTime() + 3;
moveAnimation.duration = 0.5;
moveAnimation.repeatCount = 1;
moveAnimation.removedOnCompletion = YES;
@kWeakify(self);
[moveAnimation setCompletionBlock:^(POPAnimation *anim, BOOL finished) {
@kStrongify(self);
if (finished) {
[sailingView removeFromSuperview];
if (self.sailingQueue.count > 0) {
[self.sailingQueue xpSafeRemoveObjectAtIndex:0];
}
if (self.sailingQueue.count > 0) {
[self createSailingBannerAnimation:self.sailingQueue.firstObject];
}
}
}];
[sailingView pop_addAnimation:moveAnimation forKey:@"moveOutAnimation"];
}
}];
[sailingView pop_addAnimation:springAnimation forKey:@"candyTreespingOutAnimation"];
}
- (void)receiveRoomGraffitiGift:(AttachmentModel *)attachment {
if (self.graffitiGiftQueue.count == 0) {
[self startGraffitiGiftAnimation:attachment];
}
[self.graffitiGiftQueue addObject:attachment];
}
- (void)startGraffitiGiftAnimation:(AttachmentModel *)model {
NSDictionary * dic = model.data;
NSNumber * giftId = dic[@"giftId"];
GiftInfoModel * giftInfo = [[XPGiftStorage shareStorage] findGiftInfo:giftId.stringValue inRoom:@""];
NSArray * array = dic[@"drawFixedArray"];
if (giftInfo.giftUrl.length > 0 && array.count > 0) {
[[SDWebImageManager sharedManager] loadImageWithURL:[NSURL URLWithString:giftInfo.giftUrl] options:SDWebImageProgressiveLoad progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
if (error == nil && image) {
XPRoomGraffitiGiftAnimationView *graffitiView = [[XPRoomGraffitiGiftAnimationView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
graffitiView.giftImage = image;
graffitiView.delegate = self;
graffitiView.model = model;
graffitiView.pointArray = array;
[graffitiView beginDrawAnimation];
[self.topContainer addSubview:graffitiView];
} else {
[self.graffitiGiftQueue removeObject:model];
if (self.graffitiGiftQueue.count > 0) {
[self startGraffitiGiftAnimation:self.graffitiGiftQueue.firstObject];
}
}
}];
} else {
[self.graffitiGiftQueue removeObject:model];
if (self.graffitiGiftQueue.count > 0) {
[self startGraffitiGiftAnimation:self.graffitiGiftQueue.firstObject];
}
}
}
- (void)playLuckyGiftEffectWithVapUrl:(NSString *)vapUrl {
NSString *encodingUrl = [vapUrl pureURLString];
encodingUrl = [encodingUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString *fileName = [[encodingUrl componentsSeparatedByString:@"/"] lastObject];
NSString *fullPath = [self.GiftDynamicEffectListPath stringByAppendingPathComponent:fileName];
if ([[NSFileManager defaultManager] fileExistsAtPath:fullPath]){
vapUrl = fullPath;
[self _addSubviewToMiddleContainer:self.luckyVapGiftEffectView];
[self.luckyVapGiftEffectView setMute:NO];
[self.luckyVapGiftEffectView playHWDMP4:vapUrl repeatCount:1 delegate:self];
} else {
@kWeakify(self);
[self.vapParser parseWithURL:encodingUrl completionBlock:^(NSString * _Nullable videoUrl) {
@kStrongify(self);
if (videoUrl.length) {
[self _addSubviewToMiddleContainer:self.luckyVapGiftEffectView];
[self.luckyVapGiftEffectView setMute:NO];
[self.luckyVapGiftEffectView playHWDMP4:videoUrl repeatCount:1 delegate:self];
}
} failureBlock:^(NSError * _Nullable error) {
self.luckyVapGiftEffectView.hidden = YES;
}];
}
}
-(void)playAnimationWithModel{
if(self.animationListB.count <= 0){
return;
}
if(self.isPlayOfB == YES) {
return;
}
PIBaseAnimationViewModel *model = self.animationListB.firstObject;
switch (model.type) {
case GiftBannerType_Lucky:
[self createBigPrizeAnimation:model];
break;
case GiftBannerType_Love:
[self createCandyTreeBannerAnimation:model];
break;
case GiftBannerType_Nobleman:
[self createNobleLevelUpBannerAnimation:model];
break;
case GiftBannerType_AnchorHour:
[self createAnchorHourRankAnimation:model];
break;
case GiftBannerType_LicneseHour:
[self createAnchorHourRankAnimation:model];
break;
case GiftBannerType_Fairy:
[self createTreasureFairyBannerAnimation:model];
break;
case GiftBannerType_Magic_House:
[self createGiftCompoundBannerAnimation:model];
break;
case GiftBannerType_General_Floating_Screen:
[self createGeneralFloatingScreenAnimation:model bannerModel:nil];
break;
default:
// 其他未处理的枚举值类型
// 可能包括但不限于GiftBannerType_Unknown, GiftBannerType_Normal,
// GiftBannerType_Special, GiftBannerType_Event 等
break;
}
}
- (SVGAImageView *)luckyGiftEffectView {
if (!_luckyGiftEffectView) {
_luckyGiftEffectView = [[SVGAImageView alloc]init];
_luckyGiftEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
_luckyGiftEffectView.userInteractionEnabled = NO;
_luckyGiftEffectView.delegate = self;
_luckyGiftEffectView.hidden = YES;
}
return _luckyGiftEffectView;
}
- (VAPView *)luckyVapGiftEffectView {
if (!_luckyVapGiftEffectView) {
_luckyVapGiftEffectView = [[VAPView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
_luckyVapGiftEffectView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
_luckyVapGiftEffectView.contentMode = UIViewContentModeScaleAspectFill;
_luckyVapGiftEffectView.hidden = YES;
}
return _luckyVapGiftEffectView;
}
#pragma mark - Old Methods Delegate: XPRoomGiftBroadcastViewDelegate
- (void)xPRoomGiftBroadcastView:(XPRoomGiftBroadcastView *)view enterRoom:(NSString *)roomUid roomName:(NSString *)roomName{
id isShowBroadcastView = [[NSUserDefaults standardUserDefaults]valueForKey:@"kSaveBrooadcastSelectState"];
if(isShowBroadcastView == nil){
PIRoomGiftBroadcastWindow *broadcastView = [[PIRoomGiftBroadcastWindow alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
broadcastView.roodUid = roomUid;
broadcastView.roomName = roomName;
broadcastView.delegate = self;
[kWindow addSubview:broadcastView];
return;
}
if (roomUid.length > 0 && self.hostDelegate.getRoomInfo.uid != roomUid.integerValue) {
[self.hostDelegate exitRoom];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:roomUid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
});
}
}
- (void)xPRoomLuckyBigPrizeView:(XPRoomLuckyBigPrizeView *)view luckyGiftInfo:(PIBaseAnimationViewModel *)giftInfo {
id isShowBroadcastView = [[NSUserDefaults standardUserDefaults]valueForKey:@"kSaveLuckSelectState"];
if(isShowBroadcastView == nil){
PIRoomGiftBroadcastWindow *broadcastView = [[PIRoomGiftBroadcastWindow alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, KScreenHeight)];
broadcastView.isLuck = YES;
broadcastView.roodUid = giftInfo.roomUid;
broadcastView.roomName = giftInfo.roomTitle;
broadcastView.delegate = self;
[kWindow addSubview:broadcastView];
return;
}
if (!giftInfo.isInRoomVisable && giftInfo.roomUid.length > 0 && giftInfo.roomUid.integerValue != self.hostDelegate.getRoomInfo.uid) {
[self.hostDelegate exitRoom];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:giftInfo.roomUid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
});
}
}
- (void)xPRoomAnchorRankBannerView:(XPRoomAnchorRankBannerView *)view rankInfo:(RoomHalfHourRankModel *)rankInfo{
if (rankInfo.uid.integerValue > 0 && self.hostDelegate.getRoomInfo.uid != rankInfo.uid.integerValue) {
[self.hostDelegate exitRoom];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:rankInfo.uid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
});
}
}
-(void)confirmLeaveForTheRoom:(NSString *_Nonnull)roomUid{
if (roomUid.length > 0 && self.hostDelegate.getRoomInfo.uid != roomUid.integerValue) {
[self.hostDelegate exitRoom];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:roomUid viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
});
}
}
- (void)pIUniversalBannerView:(PIUniversalBannerView *)view didClick:(PIUniversalBannerModel *)model{
if (model.skipType == 2){
[self.hostDelegate exitRoom];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[XPRoomViewController openRoom:model.skipContent viewController:[XCCurrentVCStackManager shareManager].getCurrentVC];
});
}else if (model.skipType == 3){
XPWebViewController * webVC = [[XPWebViewController alloc] initWithRoomUID:nil];
webVC.isPush = YES;
webVC.url = model.skipContent;
[self.hostDelegate.getCurrentNav pushViewController:webVC animated:YES];
}
}
- (void)xPRoomGraffitiGiftAnimationViewCompletion:(XPRoomGraffitiGiftAnimationView *)view attachment:(nonnull AttachmentModel *)attachment{
[view removeFromSuperview];
if ([self.graffitiGiftQueue containsObject:attachment]) {
[self.graffitiGiftQueue removeObject:attachment];
}
if (self.graffitiGiftQueue.count > 0) {
[self startGraffitiGiftAnimation:self.graffitiGiftQueue.firstObject];
}
}
#pragma mark - Touch Event Handling
// 移除pointInside重写让触摸事件正常传递
#pragma mark - Public Methods
- (CGPoint)getSavedTapPoint {
return self.savedTapPoint;
}
- (BOOL)hasSavedTapPointAvailable {
return self.hasSavedTapPoint;
}
- (void)clearSavedTapPoint {
self.hasSavedTapPoint = NO;
self.savedTapPoint = CGPointZero;
}
@end