From 521b5c3b7dee4cc3998814a03058c728101585ec Mon Sep 17 00:00:00 2001 From: Savya Bikram Shah Date: Sun, 7 Jun 2026 15:57:31 +0545 Subject: [PATCH] Intersterial Limit added --- .../Services/Ads/Systems/AdMobAdService.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs b/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs index 85c69b0..c7c4c54 100644 --- a/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs +++ b/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs @@ -27,12 +27,18 @@ namespace Darkmatter.Services.Ads [SerializeField, Min(1)] private int reloadMaxAttempts = 6; [Tooltip("Hard fallback (seconds) to recover a full-screen show if AdMob never raises its close callback. Android focus-return recovery usually fires far sooner; this cap covers iOS/edge cases. Must exceed max plausible ad length so a real ad is never cut short.")] [SerializeField, Min(15f)] private float showWatchdogSeconds = 60f; + [Tooltip("Max interstitials shown per app session (run). Once reached, ShowAsync(Interstitial) no-ops until the app restarts. Counts only ads actually shown, not failed/skipped attempts. 0 disables interstitials.")] + [SerializeField, Min(0)] private int maxInterstitialsPerSession = 8; public bool IsInitialized => _initialized; public event Action LoadStateChanged; private IAnalyticsService _analytics; private bool _initialized; + // Per-session interstitial counter. The service is the app-lifetime singleton (it retains + // loaded ads across scene swaps), so this survives Colorbook<->Gameplay transitions and only + // resets on app restart — i.e. a true per-session cap. + private int _interstitialsShownThisSession; private bool _hasUserConsent = true; // Coloring book is a child-directed app, so default to true. SetConsent can still // override if a consent flow later supplies a different value. @@ -189,6 +195,11 @@ namespace Darkmatter.Services.Ads if (!_initialized) return AdShowResult.Failure("Not initialized."); #if GOOGLE_MOBILE_ADS + // Per-session interstitial cap. Check before load so a capped show wastes no fill. Skip + // is silent (Failure, Shown=false); the fire-and-forget caller just keeps playing. + if (format == AdFormat.Interstitial && _interstitialsShownThisSession >= maxInterstitialsPerSession) + return AdShowResult.Failure("Session interstitial cap reached."); + if (!IsReady(format)) { bool loaded = await LoadAsync(format, cancellationToken); @@ -197,7 +208,12 @@ namespace Darkmatter.Services.Ads switch (format) { - case AdFormat.Interstitial: return await ShowInterstitialAsync(cancellationToken); + case AdFormat.Interstitial: + { + var result = await ShowInterstitialAsync(cancellationToken); + if (result.Shown) _interstitialsShownThisSession++; // count real shows only + return result; + } case AdFormat.Rewarded: return await ShowRewardedAsync(cancellationToken); case AdFormat.RewardedInterstitial: return await ShowRewardedInterstitialAsync(cancellationToken); case AdFormat.AppOpen: return await ShowAppOpenAsync(cancellationToken);