using System; using System.Collections; using ShiroginSDK.Runtime.Core.SDK; using ShiroginSDK.Runtime.Core.Utils; using ShiroginSDK.Runtime.Modules.Data.Scripts; using ShiroginSDK.Runtime.Modules.Data.Scripts.Enums; using ShiroginSDK.Runtime.Modules.Events; using ShiroginSDK.Runtime.Services.Base; using ShiroginSDK.Runtime.Services.Interfaces; using UnityEngine; namespace ShiroginSDK.Runtime.Services.Implementations.Ads { #if SHIROGIN_AD_SERVICE /// /// Handles Rewarded, Interstitial and Banner ads using AppLovin MAX SDK. /// public class AdsService : ServiceBase, IAdsService { private int _retryAttempt; private bool _canShowInterstitial; private int _addShowInterstitialTime; private Action _shouldReward; private Coroutine _interstitialCycle; private ShiroginConfig _config; private IDataService _dataService; private IEventService _eventService; // ---------------------------------------------------- // Initialization // ---------------------------------------------------- protected override void OnInitialize() { // Resolve dependencies _dataService = ServiceLocator.Get(); _eventService = ServiceLocator.Get(); _config = ShiroginConfig.Load(); #if SHIROGIN_AD_SERVICE if (!_config.enableAdService) { Debug.LogWarning("[AdsService] 🛑 Ad Service DISABLED in Config. Running in Dummy Mode."); return; } if (string.IsNullOrEmpty(_config.applovinSdkKey)) { Debug.LogError("[ShiroginSDK] Missing AppLovin SDK key in SDKConfig."); return; } MaxSdk.SetSdkKey(_config.applovinSdkKey); MaxSdk.InitializeSdk(); InitializeRewardedAds(); var storeData = _dataService.Get(); if (!storeData.HasRemovedAds) { InitializeInterstitialAds(); InitializeBannerAds(); } if (Application.internetReachability != NetworkReachability.NotReachable) _interstitialCycle = CoroutineRunner.Start(InterstitialCycle()); #else Debug.Log( "[AdsService] ⚠️ AppLovin SDK not installed or 'SHIROGIN_AD_SERVICE' not defined. Running in Headless Mode."); #endif } protected override void OnDispose() { if (_interstitialCycle != null) CoroutineRunner.Stop(_interstitialCycle); } // ---------------------------------------------------- // Rewarded Ads // ---------------------------------------------------- public bool IsRewardedReady { get { #if SHIROGIN_AD_SERVICE return MaxSdk.IsRewardedAdReady(GetRewardedId()); #endif return false; } } public void ShowRewarded(Action onComplete) { #if SHIROGIN_AD_SERVICE _shouldReward = onComplete; var economy = _dataService.Get(); if (economy.RewardedTicket > 0) { economy.SpendCurrency(CurrencyType.RewardedTicket, 1); _shouldReward?.Invoke(true); return; } if (Application.internetReachability == NetworkReachability.NotReachable) { _eventService.Invoke(new ShiroginEvents.Connection.NoConnectionEvent()); _shouldReward?.Invoke(false); return; } if (!MaxSdk.IsRewardedAdReady(GetRewardedId())) { Debug.LogWarning("[AdsService] ⚠️ Rewarded ad not ready — NoAdsAvailable event triggered."); _eventService.Invoke(new ShiroginEvents.Ads.RewardedAdUnavailableEvent()); // Popup _shouldReward?.Invoke(false); return; } MaxSdk.ShowRewardedAd(GetRewardedId()); #else if (_config == null || !_config.enableAdService) { Debug.Log("[AdsService] (Dummy) ShowRewarded called but Ads are disabled."); onComplete?.Invoke(false); return; } #endif } private void InitializeRewardedAds() { // Reset retry counter _retryAttempt = 0; // --- When ad is successfully loaded MaxSdkCallbacks.Rewarded.OnAdLoadedEvent += (adUnitId, info) => { _retryAttempt = 0; Debug.Log($"[AdsService] ✅ Rewarded loaded: {adUnitId}"); }; // --- When ad fails to load MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent += (adUnitId, error) => { _retryAttempt++; var retryDelay = Math.Pow(2, Math.Min(6, _retryAttempt)); Debug.LogWarning($"[AdsService] ⚠️ Rewarded load failed. Retrying in {retryDelay:0.0}s..."); CoroutineRunner.InvokeDelayed(LoadRewardedAd, (float)retryDelay); }; // --- When ad is displayed MaxSdkCallbacks.Rewarded.OnAdDisplayedEvent += (adUnitId, info) => { Debug.Log($"[AdsService] ▶️ Rewarded ad displayed: {adUnitId}"); }; // --- When ad fails to display MaxSdkCallbacks.Rewarded.OnAdDisplayFailedEvent += (adUnitId, error, info) => { Debug.LogError($"[AdsService] ❌ Rewarded display failed: {error.Message}"); LoadRewardedAd(); // Retry load immediately }; // --- When ad is hidden (after being watched or skipped) MaxSdkCallbacks.Rewarded.OnAdHiddenEvent += (adUnitId, info) => { Debug.Log("[AdsService] 🧹 Rewarded closed. Reloading..."); LoadRewardedAd(); // Always reload when ad is closed }; // --- When user earns reward MaxSdkCallbacks.Rewarded.OnAdReceivedRewardEvent += OnRewardedCompleted; // Initial load LoadRewardedAd(); } private void OnRewardedCompleted(string id, MaxSdkBase.Reward reward, MaxSdkBase.AdInfo info) { _shouldReward?.Invoke(true); _eventService.Invoke(new ShiroginEvents.Ads.AdAnalyticsEvent(info.NetworkName, id, info.AdFormat + "_Reward", true, info.Revenue)); _addShowInterstitialTime += 50; // ✅ Yeni reklam yükle (önemli!) LoadRewardedAd(); } private void LoadRewardedAd() { MaxSdk.LoadRewardedAd(GetRewardedId()); } // ---------------------------------------------------- // Interstitial Ads // ---------------------------------------------------- private IEnumerator InterstitialCycle() { while (true) { yield return new WaitForSeconds(180f + _addShowInterstitialTime); _canShowInterstitial = true; _addShowInterstitialTime = 0; yield return new WaitUntil(() => !_canShowInterstitial); } } private void InitializeInterstitialAds() { MaxSdkCallbacks.Interstitial.OnAdLoadedEvent += (_, _) => _retryAttempt = 0; MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent += (_, _) => { _retryAttempt++; var delay = Math.Pow(2, Math.Min(6, _retryAttempt)); CoroutineRunner.InvokeDelayed(LoadInterstitial, (float)delay); }; LoadInterstitial(); } private void LoadInterstitial() { MaxSdk.LoadInterstitial(GetInterstitialId()); } public void ShowInterstitial(bool forceShow = false) { var storeData = _dataService.Get(); #if SHIROGIN_AD_SERVICE if (storeData.HasRemovedAds) return; if ((forceShow || _canShowInterstitial) && MaxSdk.IsInterstitialReady(GetInterstitialId())) { MaxSdk.ShowInterstitial(GetInterstitialId()); LoadInterstitial(); _canShowInterstitial = false; } #else #endif } // ---------------------------------------------------- // Banner Ads // ---------------------------------------------------- private void InitializeBannerAds() { MaxSdk.CreateBanner(GetBannerId(), MaxSdkBase.BannerPosition.BottomCenter); MaxSdkCallbacks.Banner.OnAdLoadedEvent += (_, _) => { }; MaxSdkCallbacks.Banner.OnAdLoadFailedEvent += (_, _) => { }; } public void CreateBanner(bool show) { #if SHIROGIN_AD_SERVICE DestroyBanner(); MaxSdk.CreateBanner(GetBannerId(), MaxSdkBase.BannerPosition.BottomCenter); if (show) MaxSdk.ShowBanner(GetBannerId()); #endif } public void ShowBanner() { #if SHIROGIN_AD_SERVICE MaxSdk.ShowBanner(GetBannerId()); #endif } public void HideBanner() { #if SHIROGIN_AD_SERVICE MaxSdk.HideBanner(GetBannerId()); #endif } public void DestroyBanner() { #if SHIROGIN_AD_SERVICE MaxSdk.DestroyBanner(GetBannerId()); #endif } // ---------------------------------------------------- // Helpers // ---------------------------------------------------- #if UNITY_IOS private string GetRewardedId() => _config.rewardedAdUnitIdIos; private string GetInterstitialId() => _config.interstitialAdUnitIdIos; private string GetBannerId() => _config.bannerAdUnitIdIos; #else private string GetRewardedId() { return _config.rewardedAdUnitIdDrd; } private string GetInterstitialId() { return _config.interstitialAdUnitIdDrd; } private string GetBannerId() { return _config.bannerAdUnitIdDrd; } #endif } #else /// /// Handles Rewarded, Interstitial and Banner ads using AppLovin MAX SDK. /// public class AdsService : ServiceBase, IAdsService { private int _retryAttempt; private bool _canShowInterstitial; private int _addShowInterstitialTime; private Action _shouldReward; private Coroutine _interstitialCycle; private ShiroginConfig _config; private IDataService _dataService; private IEventService _eventService; // ---------------------------------------------------- // Initialization // ---------------------------------------------------- protected override void OnInitialize() { // Resolve dependencies _dataService = ServiceLocator.Get(); _eventService = ServiceLocator.Get(); _config = ShiroginConfig.Load(); Debug.Log( "[AdsService] ⚠️ AppLovin SDK not installed or 'SHIROGIN_AD_SERVICE' not defined. Running in Headless Mode."); } protected override void OnDispose() { if (_interstitialCycle != null) CoroutineRunner.Stop(_interstitialCycle); } // ---------------------------------------------------- // Rewarded Ads // ---------------------------------------------------- public bool IsRewardedReady { get { return false; } } public void ShowRewarded(Action onComplete) { if (_config == null || !_config.enableAdService) { Debug.Log("[AdsService] (Dummy) ShowRewarded called but Ads are disabled."); onComplete?.Invoke(false); return; } Debug.Log("[AdsServices] Dummy ShowRewarded"); } private void InitializeRewardedAds() { // Reset retry counter _retryAttempt = 0; // Initial load LoadRewardedAd(); } private void OnRewardedCompleted(string id, string reward, string info) { _shouldReward?.Invoke(true); _eventService.Invoke(new ShiroginEvents.Ads.AdAnalyticsEvent(info, id, info + "_Reward", true,1)); _addShowInterstitialTime += 50; LoadRewardedAd(); } private void LoadRewardedAd() { Debug.Log("[AdsServices] Dummy LoadRewardedAd"); } // ---------------------------------------------------- // Interstitial Ads // ---------------------------------------------------- private IEnumerator InterstitialCycle() { while (true) { yield return new WaitForSeconds(180f + _addShowInterstitialTime); _canShowInterstitial = true; _addShowInterstitialTime = 0; yield return new WaitUntil(() => !_canShowInterstitial); } } private void InitializeInterstitialAds() { Debug.Log("[AdsServices] Dummy InitializeInterstitialAds"); LoadInterstitial(); } private void LoadInterstitial() { Debug.Log("[AdsServices] Dummy LoadInterstitial"); } public void ShowInterstitial(bool forceShow = false) { var storeData = _dataService.Get(); Debug.Log("[AdsServices] Dummy ShowInterstitial"); } // ---------------------------------------------------- // Banner Ads // ---------------------------------------------------- private void InitializeBannerAds() { Debug.Log("[AdsServices] Dummy InitializeBannerAds"); } public void CreateBanner(bool show) { Debug.Log("[AdsServices] Dummy CreateBanner"); } public void ShowBanner() { Debug.Log("[AdsServices] Dummy ShowBanner"); } public void HideBanner() { Debug.Log("[AdsServices] Dummy HideBanner"); } public void DestroyBanner() { Debug.Log("[AdsServices] Dummy DestroyBanner"); } // ---------------------------------------------------- // Helpers // ---------------------------------------------------- #if UNITY_IOS private string GetRewardedId() => _config.rewardedAdUnitIdIos; private string GetInterstitialId() => _config.interstitialAdUnitIdIos; private string GetBannerId() => _config.bannerAdUnitIdIos; #else private string GetRewardedId() { return _config.rewardedAdUnitIdDrd; } private string GetInterstitialId() { return _config.interstitialAdUnitIdDrd; } private string GetBannerId() { return _config.bannerAdUnitIdDrd; } #endif } #endif }