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