488 lines
No EOL
15 KiB
C#
488 lines
No EOL
15 KiB
C#
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
|
|
/// <summary>
|
|
/// Handles Rewarded, Interstitial and Banner ads using AppLovin MAX SDK.
|
|
/// </summary>
|
|
public class AdsService : ServiceBase, IAdsService
|
|
{
|
|
private int _retryAttempt;
|
|
private bool _canShowInterstitial;
|
|
private int _addShowInterstitialTime;
|
|
private Action<bool> _shouldReward;
|
|
private Coroutine _interstitialCycle;
|
|
|
|
private ShiroginConfig _config;
|
|
private IDataService _dataService;
|
|
private IEventService _eventService;
|
|
|
|
// ----------------------------------------------------
|
|
// Initialization
|
|
// ----------------------------------------------------
|
|
protected override void OnInitialize()
|
|
{
|
|
// Resolve dependencies
|
|
_dataService = ServiceLocator.Get<IDataService>();
|
|
_eventService = ServiceLocator.Get<IEventService>();
|
|
|
|
_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<StoreData>();
|
|
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<bool> onComplete)
|
|
{
|
|
#if SHIROGIN_AD_SERVICE
|
|
_shouldReward = onComplete;
|
|
|
|
var economy = _dataService.Get<EconomyData>();
|
|
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<StoreData>();
|
|
|
|
#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
|
|
/// <summary>
|
|
/// Handles Rewarded, Interstitial and Banner ads using AppLovin MAX SDK.
|
|
/// </summary>
|
|
public class AdsService : ServiceBase, IAdsService
|
|
{
|
|
private int _retryAttempt;
|
|
private bool _canShowInterstitial;
|
|
private int _addShowInterstitialTime;
|
|
private Action<bool> _shouldReward;
|
|
private Coroutine _interstitialCycle;
|
|
|
|
private ShiroginConfig _config;
|
|
private IDataService _dataService;
|
|
private IEventService _eventService;
|
|
|
|
// ----------------------------------------------------
|
|
// Initialization
|
|
// ----------------------------------------------------
|
|
protected override void OnInitialize()
|
|
{
|
|
// Resolve dependencies
|
|
_dataService = ServiceLocator.Get<IDataService>();
|
|
_eventService = ServiceLocator.Get<IEventService>();
|
|
|
|
_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<bool> 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<StoreData>();
|
|
|
|
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
|
|
} |