2025-09-15 02:19:03 +00:00
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Linq ;
2025-09-15 05:58:43 +00:00
using GoogleMobileAds.Common ;
2025-09-15 02:19:03 +00:00
using JetBrains.Annotations ;
2025-09-15 10:41:43 +00:00
using KwaiAds.Scripts.Api ;
2025-09-15 05:58:43 +00:00
using KwaiAds.Scripts.Api.Interstitial ;
2025-09-15 02:19:03 +00:00
using KwaiAds.Scripts.Api.Reward ;
using UnityEngine ;
using static WZ . KwaiAdsConfigParser ;
namespace WZ
{
2025-09-15 05:58:43 +00:00
public class KwaiFloorIvManager : D_MonoSingleton < KwaiFloorIvManager >
2025-09-15 02:19:03 +00:00
{
2025-09-15 05:58:43 +00:00
private int _ivParallelRequests = 3 ;
private List < FloorConfig > _ivFloorConfigs = new List < FloorConfig > ( ) ;
public Dictionary < string , IInterstitialAdController > _ivFloorAdControllers = new Dictionary < string , IInterstitialAdController > ( ) ;
2025-09-15 02:19:03 +00:00
private List < FloorConfig > _sortedFloors = new List < FloorConfig > ( ) ;
private int _currentFloorIndex = 0 ;
private bool _isRequestingFloors = false ;
private List < FloorConfig > _currentRequestBatch = new List < FloorConfig > ( ) ;
private FloorConfig _successfulFloor = null ;
2025-09-15 05:58:43 +00:00
public float _ivStartLoadTime = 0 ;
2025-09-15 10:41:43 +00:00
private int _waterfallRequestCount = 0 ; // waterfall请求次数
2025-09-15 11:10:29 +00:00
private Dictionary < string , int > _unitIdRequestCounts = new Dictionary < string , int > ( ) ; // 每个unit_id的请求次数
2025-09-15 10:41:43 +00:00
private string _currentRequestId ; // 当前waterfall请求的ID
2025-09-15 05:58:43 +00:00
2025-09-15 02:19:03 +00:00
public void InitializeWithFloors ( )
{
// 对楼层按价格从高到低排序
2025-09-15 05:58:43 +00:00
_sortedFloors = _ivFloorConfigs . OrderByDescending ( f = > f . price ) . ToList ( ) ;
LoggerUtils . Debug ( "[kwai] floor inter Sorted floors: " + string . Join ( ", " , _sortedFloors . Select ( f = > $"{f.id}:{f.price}" ) ) ) ;
2025-09-15 02:19:03 +00:00
}
public void LoadKwaiBiddingConfig ( )
{
2025-09-15 05:58:43 +00:00
_ivParallelRequests = KwaiAdsConfigParser . GetIvParallelRequests ( ) ;
_ivFloorConfigs = KwaiAdsConfigParser . GetIvFloorConfigs ( ) ;
LoggerUtils . Debug ( $"[kwai] floor inter bidding config loaded. FloorOpen: {KwaiAdsConfigParser.GetKwaiIvFloorOpen()}, ParallelRequests: {_ivParallelRequests}, Floors: {_ivFloorConfigs.Count}" ) ;
2025-09-15 02:19:03 +00:00
}
2025-09-15 05:58:43 +00:00
public void LoadInterstitialWithFloors ( )
2025-09-15 02:19:03 +00:00
{
2025-09-15 05:58:43 +00:00
if ( _ivFloorConfigs = = null | | _ivFloorConfigs . Count = = 0 )
2025-09-15 02:19:03 +00:00
{
2025-09-15 05:58:43 +00:00
LoggerUtils . Debug ( "[kwai] floor inter No floor configs available, using standard load" ) ;
2025-09-15 02:19:03 +00:00
KwaiAdsManager . Instance . LoadRewardedStandard ( ) ;
return ;
}
2025-09-15 05:58:43 +00:00
_ivStartLoadTime = Time . realtimeSinceStartup ;
2025-09-15 02:19:03 +00:00
// 重置状态
_currentFloorIndex = 0 ;
_successfulFloor = null ;
_isRequestingFloors = true ;
2025-09-15 11:06:55 +00:00
_currentRequestId = GenerateRequestId ( ) ;
2025-09-15 02:19:03 +00:00
2025-09-15 10:41:43 +00:00
// 增加waterfall请求计数
_waterfallRequestCount + + ;
2025-09-15 02:19:03 +00:00
// 清理之前的广告控制器
2025-09-15 05:58:43 +00:00
foreach ( var controller in _ivFloorAdControllers . Values )
2025-09-15 02:19:03 +00:00
{
controller . Destroy ( ) ;
}
2025-09-15 05:58:43 +00:00
_ivFloorAdControllers . Clear ( ) ;
2025-09-15 02:19:03 +00:00
// 开始请求楼层广告
RequestNextFloorBatch ( ) ;
2025-09-16 08:19:07 +00:00
AdsActionEvents . TrackKwaiWaterfallRequest ( AdsType . Interstitial ,
_currentRequestId ,
_waterfallRequestCount ,
_ivParallelRequests ) ;
2025-09-15 02:19:03 +00:00
}
private void RequestNextFloorBatch ( )
{
if ( ! _isRequestingFloors | | _successfulFloor ! = null ) return ;
// 获取下一批要请求的楼层
_currentRequestBatch = new List < FloorConfig > ( ) ;
int count = 0 ;
2025-09-15 05:58:43 +00:00
while ( _currentFloorIndex < _sortedFloors . Count & & count < _ivParallelRequests )
2025-09-15 02:19:03 +00:00
{
_currentRequestBatch . Add ( _sortedFloors [ _currentFloorIndex ] ) ;
_currentFloorIndex + + ;
count + + ;
}
if ( _currentRequestBatch . Count = = 0 )
{
2025-09-16 08:19:07 +00:00
// 检查是否还有正在处理的请求
bool hasPendingRequests = false ;
foreach ( var kvp in _ivFloorAdControllers )
{
if ( kvp . Value ! = null & & ! kvp . Value . IsReady ( ) )
{
hasPendingRequests = true ;
break ;
}
}
if ( ! hasPendingRequests )
{
// 所有楼层都请求完毕,并且没有正在处理的请求,确实没有填充
LoggerUtils . Debug ( "[kwai] floor reward All floors requested, no fill" ) ;
_isRequestingFloors = false ;
}
2025-09-15 02:19:03 +00:00
}
2025-09-15 05:58:43 +00:00
LoggerUtils . Debug ( $"[kwai] floor inter Requesting floor batch: {string.Join(" , ", _currentRequestBatch.Select(f => $" { f . id } ( { f . price } ) "))}" ) ;
2025-09-15 02:19:03 +00:00
// 并行请求当前批次的楼层
foreach ( var floor in _currentRequestBatch )
{
RequestFloorAd ( floor ) ;
}
2025-09-16 08:19:07 +00:00
2025-09-15 02:19:03 +00:00
}
private void RequestFloorAd ( FloorConfig floor )
{
2025-09-15 10:41:43 +00:00
// 更新unite_id请求计数
2025-09-15 11:06:55 +00:00
if ( ! _unitIdRequestCounts . ContainsKey ( floor . unite_id ) )
2025-09-15 10:41:43 +00:00
{
2025-09-15 11:06:55 +00:00
_unitIdRequestCounts [ floor . unite_id ] = 0 ;
2025-09-15 10:41:43 +00:00
}
2025-09-15 11:06:55 +00:00
_unitIdRequestCounts [ floor . unite_id ] + + ;
2025-09-15 10:41:43 +00:00
// 获取当前楼层在排序列表中的位置
int floorIndex = GetFloorIndex ( floor . id ) ;
2025-09-15 11:06:55 +00:00
LoggerUtils . Debug ( $"[kwai] floor inter Requesting floor {floor.id} (index: {floorIndex}), unite_id {floor.unite_id} has been requested {_unitIdRequestCounts[floor.unite_id]} times, request id: {GetUniteIdRequestCount(floor.unite_id)}" ) ;
2025-09-15 10:41:43 +00:00
IInterstitialAdController controller = KwaiAds . Scripts . Api . KwaiAdsSdk . SDK . getInterstitialAdController ( ) ; ;
2025-09-15 05:58:43 +00:00
_ivFloorAdControllers [ floor . id ] = controller ;
KwaiInterstitialAdRequest kwaiInterstitialAdRequest = new KwaiInterstitialAdRequest ( floor . unite_id ) ;
2025-09-15 10:41:43 +00:00
kwaiInterstitialAdRequest . ExtParams [ Constants . Request . BID_FLOOR_PRICE ] = floor . price . ToString ( ) ;
2025-09-15 05:58:43 +00:00
controller . Load ( kwaiInterstitialAdRequest ,
new FloorInterAdListener ( this , floor ) ,
new FloorInterAdLoadListener ( this , floor ) ) ;
2025-09-15 11:06:55 +00:00
AdsActionEvents . TrackKwaiAdunitRequest ( AdsType . Interstitial ,
_currentRequestId ,
floor . unite_id ,
floor . price ,
GetWaterfallRequestCount ( ) ,
GetUniteIdRequestCount ( floor . unite_id ) ,
floorIndex ) ;
2025-09-15 02:19:03 +00:00
}
// 处理楼层广告加载成功
2025-09-15 11:06:55 +00:00
public void OnFloorAdLoaded ( FloorConfig floor , IInterstitialAdController controller , double revenue )
2025-09-15 02:19:03 +00:00
{
if ( ! _isRequestingFloors | | _successfulFloor ! = null ) return ;
2025-09-15 10:41:43 +00:00
// 获取当前楼层在排序列表中的位置
int floorIndex = GetFloorIndex ( floor . id ) ;
2025-09-15 11:06:55 +00:00
LoggerUtils . Debug ( $"[kwai] floor inter ad loaded: {floor.id} (index: {floorIndex}) with price: {floor.price}, unite_id {floor.unite_id} has been requested {GetUniteIdRequestCount(floor.unite_id)} times, revenue: {revenue}, request id: {_currentRequestId}" ) ;
2025-09-15 10:41:43 +00:00
2025-09-15 02:19:03 +00:00
// 暂停其他并行请求
_successfulFloor = floor ;
_isRequestingFloors = false ;
// 取消其他楼层的请求
2025-09-15 05:58:43 +00:00
foreach ( var kvp in _ivFloorAdControllers )
2025-09-15 02:19:03 +00:00
{
if ( kvp . Key ! = floor . id )
{
kvp . Value . Destroy ( ) ;
}
}
2025-09-15 11:06:55 +00:00
AdsActionEvents . TrackKwiWaterfallFill ( AdsType . Interstitial ,
_currentRequestId ,
floor . unite_id ,
floor . price ,
GetWaterfallRequestCount ( ) ,
GetUniteIdRequestCount ( floor . unite_id ) ,
floorIndex ,
revenue ) ;
2025-09-15 02:19:03 +00:00
}
// 处理楼层广告加载失败
public void OnFloorAdFailed ( FloorConfig floor , string error )
{
2025-09-16 08:19:07 +00:00
LoggerUtils . Debug ( $"[kwai] floor inter ad failed: {floor.id} with error: {error} _isRequestingFloors:{!_isRequestingFloors} _successfulFloor: {_successfulFloor != null}" ) ;
2025-09-15 02:19:03 +00:00
if ( ! _isRequestingFloors | | _successfulFloor ! = null ) return ;
2025-09-16 08:19:07 +00:00
// 移除失败floor
if ( _currentRequestBatch . Contains ( floor ) ) _currentRequestBatch . Remove ( floor ) ;
2025-09-15 02:19:03 +00:00
// 检查当前批次是否全部失败
bool allFailedInBatch = true ;
2025-09-16 08:19:07 +00:00
if ( _currentRequestBatch . Count > 0 ) allFailedInBatch = false ;
2025-09-15 02:19:03 +00:00
// 如果当前批次全部失败,请求下一批
if ( allFailedInBatch )
{
RequestNextFloorBatch ( ) ;
}
}
2025-09-15 05:58:43 +00:00
public bool IsInterstitialAdAvailable ( )
2025-09-15 02:19:03 +00:00
{
return _successfulFloor ! = null & &
2025-09-15 05:58:43 +00:00
_ivFloorAdControllers . ContainsKey ( _successfulFloor . id ) & &
_ivFloorAdControllers [ _successfulFloor . id ] ! = null & &
_ivFloorAdControllers [ _successfulFloor . id ] . IsReady ( ) ;
2025-09-15 02:19:03 +00:00
}
2025-09-15 05:58:43 +00:00
public void ShowInterstitialAd ( Action _action )
{
2025-09-15 02:19:03 +00:00
if ( _successfulFloor ! = null & &
2025-09-15 05:58:43 +00:00
_ivFloorAdControllers . ContainsKey ( _successfulFloor . id ) & &
_ivFloorAdControllers [ _successfulFloor . id ] ! = null )
2025-09-15 02:19:03 +00:00
{
2025-09-15 05:58:43 +00:00
_ivFloorAdControllers [ _successfulFloor . id ] . Show ( ) ;
2025-09-15 02:19:03 +00:00
}
else
{
_action ? . Invoke ( ) ;
}
}
2025-09-15 10:41:43 +00:00
/// <summary>
/// 获取当前waterfall请求次数
/// </summary>
public int GetWaterfallRequestCount ( )
{
return _waterfallRequestCount ;
}
/// <summary>
/// 获取当前waterfall请求次数
/// </summary>
public int GetUniteIdRequestCount ( string unitId )
{
2025-09-15 11:06:55 +00:00
return _unitIdRequestCounts . TryGetValue ( unitId , out var time ) ? time : 0 ;
2025-09-15 10:41:43 +00:00
}
/// <summary>
/// 根据floor.id获取其在排序后的楼层列表中的索引位置
/// </summary>
public int GetFloorIndex ( string floorId )
{
for ( int i = 0 ; i < _sortedFloors . Count ; i + + )
{
if ( _sortedFloors [ i ] . id = = floorId )
{
return i ;
}
}
return - 1 ; // 未找到
}
/// <summary>
/// 获取当前Request ID
/// </summary>
public string GetCurrentRequestId ( )
{
return _currentRequestId ;
}
/// <summary>
/// 生成唯一的Request ID
/// </summary>
private string GenerateRequestId ( )
{
return Guid . NewGuid ( ) . ToString ( "N" ) ;
}
2025-09-15 02:19:03 +00:00
}
}