diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Ads.meta b/Assets/Darkmatter/Code/Core/Contracts/Services/Ads.meta new file mode 100644 index 0000000..a988e8d --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Ads.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 683c2f491e8042d0a46bb7b5ad497be3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Ads/IAdService.cs b/Assets/Darkmatter/Code/Core/Contracts/Services/Ads/IAdService.cs new file mode 100644 index 0000000..01a4e48 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Ads/IAdService.cs @@ -0,0 +1,26 @@ +using System; +using System.Threading; +using Cysharp.Threading.Tasks; +using Darkmatter.Core.Data.Dynamic.Services.Ads; +using Darkmatter.Core.Enums.Services.Ads; + +namespace Darkmatter.Core.Contracts.Services.Ads +{ + public interface IAdService + { + bool IsInitialized { get; } + event Action LoadStateChanged; + + UniTask InitializeAsync(CancellationToken cancellationToken); + + UniTask LoadAsync(AdFormat format, CancellationToken cancellationToken); + bool IsReady(AdFormat format); + UniTask ShowAsync(AdFormat format, CancellationToken cancellationToken); + + UniTask ShowBannerAsync(BannerSize size, BannerPosition position, CancellationToken cancellationToken); + void HideBanner(); + void DestroyBanner(); + + void SetConsent(bool hasUserConsent, bool isChildDirected); + } +} diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Ads/IAdService.cs.meta b/Assets/Darkmatter/Code/Core/Contracts/Services/Ads/IAdService.cs.meta new file mode 100644 index 0000000..761b6fe --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Ads/IAdService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ffaede2f106c45a68197d70ec929c7de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads.meta b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads.meta new file mode 100644 index 0000000..7f3b38b --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 868c1ce3a8b740a8aa4949fe685a1dcc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdReward.cs b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdReward.cs new file mode 100644 index 0000000..c5e6513 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdReward.cs @@ -0,0 +1,14 @@ +namespace Darkmatter.Core.Data.Dynamic.Services.Ads +{ + public readonly struct AdReward + { + public readonly string Type; + public readonly double Amount; + + public AdReward(string type, double amount) + { + Type = type; + Amount = amount; + } + } +} diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdReward.cs.meta b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdReward.cs.meta new file mode 100644 index 0000000..842304b --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdReward.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 784af4bbe9df4c25b5d304d8364ade62 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdShowResult.cs b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdShowResult.cs new file mode 100644 index 0000000..246de52 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdShowResult.cs @@ -0,0 +1,22 @@ +namespace Darkmatter.Core.Data.Dynamic.Services.Ads +{ + public readonly struct AdShowResult + { + public readonly bool Shown; + public readonly bool Rewarded; + public readonly AdReward Reward; + public readonly string Error; + + public AdShowResult(bool shown, bool rewarded, AdReward reward, string error) + { + Shown = shown; + Rewarded = rewarded; + Reward = reward; + Error = error; + } + + public static AdShowResult Success() => new(true, false, default, null); + public static AdShowResult WithReward(AdReward reward) => new(true, true, reward, null); + public static AdShowResult Failure(string error) => new(false, false, default, error); + } +} diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdShowResult.cs.meta b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdShowResult.cs.meta new file mode 100644 index 0000000..c87afdd --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Ads/AdShowResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2859963572b4173957a583249f5d399 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Services/Ads.meta b/Assets/Darkmatter/Code/Core/Data/Static/Services/Ads.meta new file mode 100644 index 0000000..c2dc952 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static/Services/Ads.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4dcdb224825b4764a080e5b881b996e4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Services/Ads/AdUnitCatalogSO.cs b/Assets/Darkmatter/Code/Core/Data/Static/Services/Ads/AdUnitCatalogSO.cs new file mode 100644 index 0000000..020a1b1 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static/Services/Ads/AdUnitCatalogSO.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using Darkmatter.Core.Enums.Services.Ads; +using UnityEngine; + +namespace Darkmatter.Core.Data.Static.Services.Ads +{ + [CreateAssetMenu(fileName = "AdUnitCatalog", menuName = "Darkmatter/Ads/Ad Unit Catalog")] + public class AdUnitCatalogSO : ScriptableObject + { + [Serializable] + public class Entry + { + public AdFormat Format; + public string AndroidUnitId; + public string IosUnitId; + } + + [Header("App IDs")] + [SerializeField] private string androidAppId; + [SerializeField] private string iosAppId; + + [Header("Test Mode")] + [Tooltip("If true, returns Google sample ad unit IDs (safe for development).")] + [SerializeField] private bool useTestUnits = true; + + [Tooltip("Device IDs to treat as test devices (hashed IDs from logcat).")] + [SerializeField] private List testDeviceIds = new(); + + [Header("Production Unit IDs")] + [SerializeField] private List entries = new(); + + public string AndroidAppId => androidAppId; + public string IosAppId => iosAppId; + public bool UseTestUnits => useTestUnits; + public IReadOnlyList TestDeviceIds => testDeviceIds; + + public string GetUnitId(AdFormat format, RuntimePlatform platform) + { + if (useTestUnits) + { + return GetTestUnitId(format, platform); + } + + foreach (var e in entries) + { + if (e == null || e.Format != format) continue; + return platform == RuntimePlatform.IPhonePlayer ? e.IosUnitId : e.AndroidUnitId; + } + return null; + } + + private static string GetTestUnitId(AdFormat format, RuntimePlatform platform) + { + bool ios = platform == RuntimePlatform.IPhonePlayer; + return format switch + { + AdFormat.Banner => ios ? "ca-app-pub-3940256099942544/2934735716" : "ca-app-pub-3940256099942544/6300978111", + AdFormat.Interstitial => ios ? "ca-app-pub-3940256099942544/4411468910" : "ca-app-pub-3940256099942544/1033173712", + AdFormat.Rewarded => ios ? "ca-app-pub-3940256099942544/1712485313" : "ca-app-pub-3940256099942544/5224354917", + AdFormat.RewardedInterstitial => ios ? "ca-app-pub-3940256099942544/6978759866" : "ca-app-pub-3940256099942544/5354046379", + AdFormat.AppOpen => ios ? "ca-app-pub-3940256099942544/5575463023" : "ca-app-pub-3940256099942544/9257395921", + _ => null + }; + } + } +} diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Services/Ads/AdUnitCatalogSO.cs.meta b/Assets/Darkmatter/Code/Core/Data/Static/Services/Ads/AdUnitCatalogSO.cs.meta new file mode 100644 index 0000000..0b6ed04 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static/Services/Ads/AdUnitCatalogSO.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e6352f0162df4adf99a5945e25c6bf40 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Ads.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Ads.meta new file mode 100644 index 0000000..28be429 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Ads.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 40846ca6e71249d68a99e1d226fd162d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdFormat.cs b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdFormat.cs new file mode 100644 index 0000000..6e669f0 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdFormat.cs @@ -0,0 +1,11 @@ +namespace Darkmatter.Core.Enums.Services.Ads +{ + public enum AdFormat + { + Banner, + Interstitial, + Rewarded, + RewardedInterstitial, + AppOpen + } +} diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdFormat.cs.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdFormat.cs.meta new file mode 100644 index 0000000..4df66a5 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdFormat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce1e736d19fc4569af80b06274dc3935 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdLoadState.cs b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdLoadState.cs new file mode 100644 index 0000000..16ea894 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdLoadState.cs @@ -0,0 +1,10 @@ +namespace Darkmatter.Core.Enums.Services.Ads +{ + public enum AdLoadState + { + Idle, + Loading, + Loaded, + Failed + } +} diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdLoadState.cs.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdLoadState.cs.meta new file mode 100644 index 0000000..5d26424 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/AdLoadState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44f09c3955b34814abfa83407118a6a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerPosition.cs b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerPosition.cs new file mode 100644 index 0000000..4dd4833 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerPosition.cs @@ -0,0 +1,13 @@ +namespace Darkmatter.Core.Enums.Services.Ads +{ + public enum BannerPosition + { + Top, + Bottom, + TopLeft, + TopRight, + BottomLeft, + BottomRight, + Center + } +} diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerPosition.cs.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerPosition.cs.meta new file mode 100644 index 0000000..1423c11 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerPosition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2223e7f2cedb4f479f7c6722e0ca7fd1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerSize.cs b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerSize.cs new file mode 100644 index 0000000..79aa47c --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerSize.cs @@ -0,0 +1,13 @@ +namespace Darkmatter.Core.Enums.Services.Ads +{ + public enum BannerSize + { + Banner, + LargeBanner, + MediumRectangle, + FullBanner, + Leaderboard, + SmartBanner, + AnchoredAdaptive + } +} diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerSize.cs.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerSize.cs.meta new file mode 100644 index 0000000..3276742 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Ads/BannerSize.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 570a6e9b47c5451c8ef78aa7a3923ead +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Services/Ads.meta b/Assets/Darkmatter/Code/Services/Ads.meta new file mode 100644 index 0000000..d2c3bcd --- /dev/null +++ b/Assets/Darkmatter/Code/Services/Ads.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3a320ad839a14f578bb9ff149807ed84 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Services/Ads/Installers.meta b/Assets/Darkmatter/Code/Services/Ads/Installers.meta new file mode 100644 index 0000000..0d8fccd --- /dev/null +++ b/Assets/Darkmatter/Code/Services/Ads/Installers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fd05451b7a0c4e04ae9521e8052ee1e2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Services/Ads/Installers/AdServiceModule.cs b/Assets/Darkmatter/Code/Services/Ads/Installers/AdServiceModule.cs new file mode 100644 index 0000000..372cd66 --- /dev/null +++ b/Assets/Darkmatter/Code/Services/Ads/Installers/AdServiceModule.cs @@ -0,0 +1,31 @@ +using Darkmatter.Core.Contracts.Services.Ads; +using Darkmatter.Core.Data.Static.Services.Ads; +using Darkmatter.Libs.Installers; +using UnityEngine; +using VContainer; +using VContainer.Unity; + +namespace Darkmatter.Services.Ads +{ + public class AdServiceModule : MonoBehaviour, IModule + { + [SerializeField] private AdUnitCatalogSO adUnitCatalog; + [SerializeField] private AdMobAdService adService; + + public void Register(IContainerBuilder builder) + { + if (adUnitCatalog != null) + builder.RegisterComponent(adUnitCatalog); + + var resolved = adService; + if (resolved == null) resolved = GetComponent(); + if (resolved == null) resolved = GetComponentInChildren(includeInactive: true); + if (resolved == null) resolved = FindFirstObjectByType(FindObjectsInactive.Include); + + if (resolved != null) + builder.RegisterComponent(resolved); + else + Debug.LogError("[AdServiceModule] No AdMobAdService component found. Assign 'adService' field or add AdMobAdService MonoBehaviour to scene."); + } + } +} diff --git a/Assets/Darkmatter/Code/Services/Ads/Installers/AdServiceModule.cs.meta b/Assets/Darkmatter/Code/Services/Ads/Installers/AdServiceModule.cs.meta new file mode 100644 index 0000000..d4e8ad2 --- /dev/null +++ b/Assets/Darkmatter/Code/Services/Ads/Installers/AdServiceModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a17cb41935543a6b4f67be8f398d774 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Services/Ads/Services.Ads.asmdef b/Assets/Darkmatter/Code/Services/Ads/Services.Ads.asmdef new file mode 100644 index 0000000..1c756d3 --- /dev/null +++ b/Assets/Darkmatter/Code/Services/Ads/Services.Ads.asmdef @@ -0,0 +1,25 @@ +{ + "name": "Services.Ads", + "rootNamespace": "Darkmatter.Services.Ads", + "references": [ + "GUID:6a0a834eb41764f12ba55c3fb04a40cb", + "GUID:f51ebe6a0ceec4240a699833d6309b23", + "GUID:b0214a6008ed146ff8f122a6a9c2f6cc", + "GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.google.ads.mobile", + "expression": "1.0.0", + "define": "GOOGLE_MOBILE_ADS" + } + ], + "noEngineReferences": false +} diff --git a/Assets/Darkmatter/Code/Services/Ads/Services.Ads.asmdef.meta b/Assets/Darkmatter/Code/Services/Ads/Services.Ads.asmdef.meta new file mode 100644 index 0000000..83b20cf --- /dev/null +++ b/Assets/Darkmatter/Code/Services/Ads/Services.Ads.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 662a8e56a1724c84ad8c10211211f0d5 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Services/Ads/Systems.meta b/Assets/Darkmatter/Code/Services/Ads/Systems.meta new file mode 100644 index 0000000..69b031f --- /dev/null +++ b/Assets/Darkmatter/Code/Services/Ads/Systems.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6fbb9ad075cb419095482b3d74c4311c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs b/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs new file mode 100644 index 0000000..3bbb74e --- /dev/null +++ b/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs @@ -0,0 +1,534 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Cysharp.Threading.Tasks; +using Darkmatter.Core.Contracts.Services.Ads; +using Darkmatter.Core.Data.Dynamic.Services.Ads; +using Darkmatter.Core.Data.Static.Services.Ads; +using Darkmatter.Core.Enums.Services.Ads; +using UnityEngine; +#if GOOGLE_MOBILE_ADS +using GoogleMobileAds.Api; +#endif + +namespace Darkmatter.Services.Ads +{ + public class AdMobAdService : MonoBehaviour, IAdService + { + [SerializeField] private AdUnitCatalogSO catalog; + [Tooltip("Auto-reload after dismiss/failure for non-banner formats.")] + [SerializeField] private bool autoReload = true; + [Tooltip("Seconds between auto-reload retries on failure.")] + [SerializeField, Min(1f)] private float reloadDelaySeconds = 5f; + + public bool IsInitialized => _initialized; + public event Action LoadStateChanged; + + private bool _initialized; + private bool _hasUserConsent = true; + private bool _isChildDirected; + private CancellationTokenSource _lifetimeCts; + + private readonly Dictionary _states = new(); + +#if GOOGLE_MOBILE_ADS + private InterstitialAd _interstitial; + private RewardedAd _rewarded; + private RewardedInterstitialAd _rewardedInterstitial; + private AppOpenAd _appOpen; + private BannerView _banner; +#endif + + private void Awake() + { + _lifetimeCts = new CancellationTokenSource(); + foreach (AdFormat fmt in Enum.GetValues(typeof(AdFormat))) + _states[fmt] = AdLoadState.Idle; + } + + private void OnDestroy() + { + _lifetimeCts?.Cancel(); + _lifetimeCts?.Dispose(); + _lifetimeCts = null; + +#if GOOGLE_MOBILE_ADS + _interstitial?.Destroy(); + _rewarded?.Destroy(); + _rewardedInterstitial?.Destroy(); + _appOpen?.Destroy(); + _banner?.Destroy(); +#endif + } + + public async UniTask InitializeAsync(CancellationToken cancellationToken) + { + if (_initialized) return; + if (catalog == null) + { + Debug.LogError("[AdMobAdService] No AdUnitCatalogSO assigned."); + return; + } + +#if GOOGLE_MOBILE_ADS + ApplyRequestConfiguration(); + + var tcs = new UniTaskCompletionSource(); + MobileAds.Initialize(_ => tcs.TrySetResult(true)); + + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + { + await tcs.Task; + } + + _initialized = true; + Debug.Log("[AdMobAdService] Initialized."); +#else + await UniTask.CompletedTask; + _initialized = true; + Debug.LogWarning("[AdMobAdService] GOOGLE_MOBILE_ADS not defined. Service will no-op. Add scripting define after importing Google Mobile Ads SDK."); +#endif + } + + public async UniTask LoadAsync(AdFormat format, CancellationToken cancellationToken) + { + if (!_initialized) + { + Debug.LogWarning("[AdMobAdService] Load called before init."); + return false; + } + +#if GOOGLE_MOBILE_ADS + string unitId = catalog.GetUnitId(format, Application.platform); + if (string.IsNullOrEmpty(unitId)) + { + Debug.LogWarning($"[AdMobAdService] No unit ID for {format} on {Application.platform}."); + return false; + } + + SetState(format, AdLoadState.Loading); + var request = new AdRequest(); + + switch (format) + { + case AdFormat.Interstitial: + return await LoadInterstitialAsync(unitId, request, cancellationToken); + case AdFormat.Rewarded: + return await LoadRewardedAsync(unitId, request, cancellationToken); + case AdFormat.RewardedInterstitial: + return await LoadRewardedInterstitialAsync(unitId, request, cancellationToken); + case AdFormat.AppOpen: + return await LoadAppOpenAsync(unitId, request, cancellationToken); + case AdFormat.Banner: + Debug.LogWarning("[AdMobAdService] Use ShowBannerAsync for banners."); + SetState(format, AdLoadState.Failed); + return false; + } + return false; +#else + await UniTask.CompletedTask; + SetState(format, AdLoadState.Failed); + return false; +#endif + } + + public bool IsReady(AdFormat format) + { + if (!_initialized) return false; +#if GOOGLE_MOBILE_ADS + return format switch + { + AdFormat.Interstitial => _interstitial != null && _interstitial.CanShowAd(), + AdFormat.Rewarded => _rewarded != null && _rewarded.CanShowAd(), + AdFormat.RewardedInterstitial => _rewardedInterstitial != null && _rewardedInterstitial.CanShowAd(), + AdFormat.AppOpen => _appOpen != null && _appOpen.CanShowAd(), + _ => false + }; +#else + return false; +#endif + } + + public async UniTask ShowAsync(AdFormat format, CancellationToken cancellationToken) + { + if (!_initialized) return AdShowResult.Failure("Not initialized."); + +#if GOOGLE_MOBILE_ADS + if (!IsReady(format)) + { + bool loaded = await LoadAsync(format, cancellationToken); + if (!loaded) return AdShowResult.Failure($"{format} failed to load."); + } + + switch (format) + { + case AdFormat.Interstitial: return await ShowInterstitialAsync(cancellationToken); + case AdFormat.Rewarded: return await ShowRewardedAsync(cancellationToken); + case AdFormat.RewardedInterstitial: return await ShowRewardedInterstitialAsync(cancellationToken); + case AdFormat.AppOpen: return await ShowAppOpenAsync(cancellationToken); + } + return AdShowResult.Failure($"{format} not supported by ShowAsync."); +#else + await UniTask.CompletedTask; + return AdShowResult.Failure("GOOGLE_MOBILE_ADS not defined."); +#endif + } + + public async UniTask ShowBannerAsync(BannerSize size, BannerPosition position, CancellationToken cancellationToken) + { + if (!_initialized) return false; + +#if GOOGLE_MOBILE_ADS + string unitId = catalog.GetUnitId(AdFormat.Banner, Application.platform); + if (string.IsNullOrEmpty(unitId)) return false; + + _banner?.Destroy(); + _banner = new BannerView(unitId, MapBannerSize(size), MapBannerPosition(position)); + + var tcs = new UniTaskCompletionSource(); + _banner.OnBannerAdLoaded += () => tcs.TrySetResult(true); + _banner.OnBannerAdLoadFailed += err => + { + Debug.LogWarning($"[AdMobAdService] Banner load failed: {err}"); + tcs.TrySetResult(false); + }; + + SetState(AdFormat.Banner, AdLoadState.Loading); + _banner.LoadAd(new AdRequest()); + + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + { + bool ok = await tcs.Task; + SetState(AdFormat.Banner, ok ? AdLoadState.Loaded : AdLoadState.Failed); + return ok; + } +#else + await UniTask.CompletedTask; + return false; +#endif + } + + public void HideBanner() + { +#if GOOGLE_MOBILE_ADS + _banner?.Hide(); +#endif + } + + public void DestroyBanner() + { +#if GOOGLE_MOBILE_ADS + _banner?.Destroy(); + _banner = null; + SetState(AdFormat.Banner, AdLoadState.Idle); +#endif + } + + public void SetConsent(bool hasUserConsent, bool isChildDirected) + { + _hasUserConsent = hasUserConsent; + _isChildDirected = isChildDirected; +#if GOOGLE_MOBILE_ADS + if (_initialized) ApplyRequestConfiguration(); +#endif + } + +#if GOOGLE_MOBILE_ADS + private void ApplyRequestConfiguration() + { + var config = new RequestConfiguration + { + TagForChildDirectedTreatment = _isChildDirected + ? TagForChildDirectedTreatment.True + : TagForChildDirectedTreatment.Unspecified, + TagForUnderAgeOfConsent = _hasUserConsent + ? TagForUnderAgeOfConsent.Unspecified + : TagForUnderAgeOfConsent.True + }; + + if (catalog.TestDeviceIds is { Count: > 0 }) + { + config.TestDeviceIds = new List(catalog.TestDeviceIds); + } + + MobileAds.SetRequestConfiguration(config); + } + + private async UniTask LoadInterstitialAsync(string unitId, AdRequest request, CancellationToken cancellationToken) + { + var tcs = new UniTaskCompletionSource(); + InterstitialAd.Load(unitId, request, (ad, error) => + { + if (error != null || ad == null) + { + Debug.LogWarning($"[AdMobAdService] Interstitial load failed: {error}"); + tcs.TrySetResult(false); + return; + } + _interstitial?.Destroy(); + _interstitial = ad; + WireFullScreenEvents(ad, AdFormat.Interstitial); + tcs.TrySetResult(true); + }); + + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + { + bool ok = await tcs.Task; + SetState(AdFormat.Interstitial, ok ? AdLoadState.Loaded : AdLoadState.Failed); + return ok; + } + } + + private async UniTask LoadRewardedAsync(string unitId, AdRequest request, CancellationToken cancellationToken) + { + var tcs = new UniTaskCompletionSource(); + RewardedAd.Load(unitId, request, (ad, error) => + { + if (error != null || ad == null) + { + Debug.LogWarning($"[AdMobAdService] Rewarded load failed: {error}"); + tcs.TrySetResult(false); + return; + } + _rewarded?.Destroy(); + _rewarded = ad; + WireFullScreenEvents(ad, AdFormat.Rewarded); + tcs.TrySetResult(true); + }); + + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + { + bool ok = await tcs.Task; + SetState(AdFormat.Rewarded, ok ? AdLoadState.Loaded : AdLoadState.Failed); + return ok; + } + } + + private async UniTask LoadRewardedInterstitialAsync(string unitId, AdRequest request, CancellationToken cancellationToken) + { + var tcs = new UniTaskCompletionSource(); + RewardedInterstitialAd.Load(unitId, request, (ad, error) => + { + if (error != null || ad == null) + { + Debug.LogWarning($"[AdMobAdService] RewardedInterstitial load failed: {error}"); + tcs.TrySetResult(false); + return; + } + _rewardedInterstitial?.Destroy(); + _rewardedInterstitial = ad; + WireFullScreenEvents(ad, AdFormat.RewardedInterstitial); + tcs.TrySetResult(true); + }); + + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + { + bool ok = await tcs.Task; + SetState(AdFormat.RewardedInterstitial, ok ? AdLoadState.Loaded : AdLoadState.Failed); + return ok; + } + } + + private async UniTask LoadAppOpenAsync(string unitId, AdRequest request, CancellationToken cancellationToken) + { + var tcs = new UniTaskCompletionSource(); + AppOpenAd.Load(unitId, request, (ad, error) => + { + if (error != null || ad == null) + { + Debug.LogWarning($"[AdMobAdService] AppOpen load failed: {error}"); + tcs.TrySetResult(false); + return; + } + _appOpen?.Destroy(); + _appOpen = ad; + WireFullScreenEvents(ad, AdFormat.AppOpen); + tcs.TrySetResult(true); + }); + + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + { + bool ok = await tcs.Task; + SetState(AdFormat.AppOpen, ok ? AdLoadState.Loaded : AdLoadState.Failed); + return ok; + } + } + + private async UniTask ShowInterstitialAsync(CancellationToken cancellationToken) + { + var tcs = new UniTaskCompletionSource(); + Action onClosed = () => tcs.TrySetResult(AdShowResult.Success()); + Action onFailed = err => tcs.TrySetResult(AdShowResult.Failure(err?.GetMessage())); + + _interstitial.OnAdFullScreenContentClosed += onClosed; + _interstitial.OnAdFullScreenContentFailed += onFailed; + _interstitial.Show(); + + try + { + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + return await tcs.Task; + } + finally + { + if (_interstitial != null) + { + _interstitial.OnAdFullScreenContentClosed -= onClosed; + _interstitial.OnAdFullScreenContentFailed -= onFailed; + } + ScheduleReload(AdFormat.Interstitial); + } + } + + private async UniTask ShowRewardedAsync(CancellationToken cancellationToken) + { + var tcs = new UniTaskCompletionSource(); + bool earned = false; + AdReward reward = default; + + Action onClosed = () => tcs.TrySetResult(earned ? AdShowResult.WithReward(reward) : AdShowResult.Success()); + Action onFailed = err => tcs.TrySetResult(AdShowResult.Failure(err?.GetMessage())); + + _rewarded.OnAdFullScreenContentClosed += onClosed; + _rewarded.OnAdFullScreenContentFailed += onFailed; + _rewarded.Show(r => + { + earned = true; + reward = new AdReward(r.Type, r.Amount); + }); + + try + { + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + return await tcs.Task; + } + finally + { + if (_rewarded != null) + { + _rewarded.OnAdFullScreenContentClosed -= onClosed; + _rewarded.OnAdFullScreenContentFailed -= onFailed; + } + ScheduleReload(AdFormat.Rewarded); + } + } + + private async UniTask ShowRewardedInterstitialAsync(CancellationToken cancellationToken) + { + var tcs = new UniTaskCompletionSource(); + bool earned = false; + AdReward reward = default; + + Action onClosed = () => tcs.TrySetResult(earned ? AdShowResult.WithReward(reward) : AdShowResult.Success()); + Action onFailed = err => tcs.TrySetResult(AdShowResult.Failure(err?.GetMessage())); + + _rewardedInterstitial.OnAdFullScreenContentClosed += onClosed; + _rewardedInterstitial.OnAdFullScreenContentFailed += onFailed; + _rewardedInterstitial.Show(r => + { + earned = true; + reward = new AdReward(r.Type, r.Amount); + }); + + try + { + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + return await tcs.Task; + } + finally + { + if (_rewardedInterstitial != null) + { + _rewardedInterstitial.OnAdFullScreenContentClosed -= onClosed; + _rewardedInterstitial.OnAdFullScreenContentFailed -= onFailed; + } + ScheduleReload(AdFormat.RewardedInterstitial); + } + } + + private async UniTask ShowAppOpenAsync(CancellationToken cancellationToken) + { + var tcs = new UniTaskCompletionSource(); + Action onClosed = () => tcs.TrySetResult(AdShowResult.Success()); + Action onFailed = err => tcs.TrySetResult(AdShowResult.Failure(err?.GetMessage())); + + _appOpen.OnAdFullScreenContentClosed += onClosed; + _appOpen.OnAdFullScreenContentFailed += onFailed; + _appOpen.Show(); + + try + { + using (cancellationToken.Register(() => tcs.TrySetCanceled(cancellationToken))) + return await tcs.Task; + } + finally + { + if (_appOpen != null) + { + _appOpen.OnAdFullScreenContentClosed -= onClosed; + _appOpen.OnAdFullScreenContentFailed -= onFailed; + } + ScheduleReload(AdFormat.AppOpen); + } + } + + private void WireFullScreenEvents(InterstitialAd ad, AdFormat format) => + ad.OnAdFullScreenContentClosed += () => SetState(format, AdLoadState.Idle); + + private void WireFullScreenEvents(RewardedAd ad, AdFormat format) => + ad.OnAdFullScreenContentClosed += () => SetState(format, AdLoadState.Idle); + + private void WireFullScreenEvents(RewardedInterstitialAd ad, AdFormat format) => + ad.OnAdFullScreenContentClosed += () => SetState(format, AdLoadState.Idle); + + private void WireFullScreenEvents(AppOpenAd ad, AdFormat format) => + ad.OnAdFullScreenContentClosed += () => SetState(format, AdLoadState.Idle); + + private void ScheduleReload(AdFormat format) + { + if (!autoReload || _lifetimeCts == null) return; + ReloadAfterDelayAsync(format, _lifetimeCts.Token).Forget(); + } + + private async UniTaskVoid ReloadAfterDelayAsync(AdFormat format, CancellationToken cancellationToken) + { + try + { + await UniTask.Delay(TimeSpan.FromSeconds(reloadDelaySeconds), cancellationToken: cancellationToken); + await LoadAsync(format, cancellationToken); + } + catch (OperationCanceledException) { } + } + + private static AdSize MapBannerSize(BannerSize size) => size switch + { + BannerSize.Banner => AdSize.Banner, + BannerSize.LargeBanner => AdSize.LargeBanner, + BannerSize.MediumRectangle => AdSize.MediumRectangle, + BannerSize.FullBanner => AdSize.IABBanner, + BannerSize.Leaderboard => AdSize.Leaderboard, + BannerSize.SmartBanner => AdSize.SmartBanner, + BannerSize.AnchoredAdaptive => AdSize.GetCurrentOrientationAnchoredAdaptiveBannerAdSizeWithWidth(AdSize.FullWidth), + _ => AdSize.Banner + }; + + private static AdPosition MapBannerPosition(BannerPosition position) => position switch + { + BannerPosition.Top => AdPosition.Top, + BannerPosition.Bottom => AdPosition.Bottom, + BannerPosition.TopLeft => AdPosition.TopLeft, + BannerPosition.TopRight => AdPosition.TopRight, + BannerPosition.BottomLeft => AdPosition.BottomLeft, + BannerPosition.BottomRight => AdPosition.BottomRight, + BannerPosition.Center => AdPosition.Center, + _ => AdPosition.Bottom + }; +#endif + + private void SetState(AdFormat format, AdLoadState state) + { + _states[format] = state; + LoadStateChanged?.Invoke(format, state); + } + } +} diff --git a/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs.meta b/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs.meta new file mode 100644 index 0000000..74f94e2 --- /dev/null +++ b/Assets/Darkmatter/Code/Services/Ads/Systems/AdMobAdService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 018ba83ad51c4d9a89a904ba3d21ead2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Content/Colorbook UI/Prefabs/DrawingPrefabs/DogDrawing.prefab b/Assets/Darkmatter/Content/Colorbook UI/Prefabs/DrawingPrefabs/DogDrawing.prefab index 9dd81a0..5dfaf98 100644 --- a/Assets/Darkmatter/Content/Colorbook UI/Prefabs/DrawingPrefabs/DogDrawing.prefab +++ b/Assets/Darkmatter/Content/Colorbook UI/Prefabs/DrawingPrefabs/DogDrawing.prefab @@ -113,8 +113,6 @@ RectTransform: - {fileID: 8154963574219759720} - {fileID: 7351436046237102377} - {fileID: 8023488669259040938} - - {fileID: 5195340575954518351} - - {fileID: 9198769832469663334} - {fileID: 4191763766181402144} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -493,242 +491,6 @@ RectTransform: m_CorrespondingSourceObject: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} m_PrefabInstance: {fileID: 1502616118055275403} m_PrefabAsset: {fileID: 0} ---- !u!1001 &3099294300521518637 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - serializedVersion: 3 - m_TransformParent: {fileID: 8646486881233576619} - m_Modifications: - - target: {fileID: 3388453239853753565, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_Name - value: Nose (1) - objectReference: {fileID: 0} - - target: {fileID: 3388453239853753565, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_IsActive - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_Pivot.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_Pivot.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_AnchorMax.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_AnchorMax.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_AnchorMin.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_AnchorMin.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_SizeDelta.x - value: 64.83 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_SizeDelta.y - value: 53.184 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalScale.x - value: 1.7513999 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalScale.y - value: 1.7513999 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalScale.z - value: 1.7513999 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_AnchoredPosition.x - value: -730.2462 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_AnchoredPosition.y - value: 322.0824 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_RemovedGameObjects: [] - m_AddedGameObjects: [] - m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} ---- !u!224 &5195340575954518351 stripped -RectTransform: - m_CorrespondingSourceObject: {fileID: 7141417102443485026, guid: 4d7801ac4730f46b6ba82c8025ebd177, type: 3} - m_PrefabInstance: {fileID: 3099294300521518637} - m_PrefabAsset: {fileID: 0} ---- !u!1001 &4768500294296056210 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - serializedVersion: 3 - m_TransformParent: {fileID: 8646486881233576619} - m_Modifications: - - target: {fileID: 4279528263583881541, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_Name - value: Teeth - objectReference: {fileID: 0} - - target: {fileID: 4279528263583881541, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_IsActive - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_Pivot.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_Pivot.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_AnchorMax.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_AnchorMax.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_AnchorMin.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_AnchorMin.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_SizeDelta.x - value: 73.699 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_SizeDelta.y - value: 16.612 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalScale.x - value: 1.7513999 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalScale.y - value: 1.7513999 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalScale.z - value: 1.7513999 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalRotation.x - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalRotation.y - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalRotation.z - value: -0 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_AnchoredPosition.x - value: -722.48737 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_AnchoredPosition.y - value: 200.17633 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_RemovedGameObjects: [] - m_AddedGameObjects: [] - m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} ---- !u!224 &9198769832469663334 stripped -RectTransform: - m_CorrespondingSourceObject: {fileID: 4433096382570807284, guid: 70aa2daf45f0649c2823d1930e906f59, type: 3} - m_PrefabInstance: {fileID: 4768500294296056210} - m_PrefabAsset: {fileID: 0} --- !u!1001 &5308332954791877727 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Darkmatter/Data/Drawings/Templates/Ball.asset b/Assets/Darkmatter/Data/Drawings/Templates/Ball.asset index 4fc9768..1e5ea2d 100644 --- a/Assets/Darkmatter/Data/Drawings/Templates/Ball.asset +++ b/Assets/Darkmatter/Data/Drawings/Templates/Ball.asset @@ -17,7 +17,7 @@ MonoBehaviour: defaultThumbnail: {fileID: 21300000, guid: c79f0374ffc23654fa0c341985d7e249, type: 3} drawingPrefab: {fileID: 3523649744351506124, guid: ed2c3db5a20de9643a04dca1c61ff246, type: 3} coloringPrefab: {fileID: 6799536857748686187, guid: e02814fe96e1cf84491b9545b5642307, type: 3} - completionAnimationPrefab: {fileID: 0} + completionAnimationPrefab: {fileID: 6152354576180930737, guid: 4ae77336fb29049ef91d839f601fca8a, type: 3} pieces: - {fileID: 11400000, guid: a3dc108a48b1e4f2196e8d49ae8e3edd, type: 2} regions: diff --git a/Assets/Darkmatter/Data/Drawings/Templates/Dog.asset b/Assets/Darkmatter/Data/Drawings/Templates/Dog.asset index 5189493..520efa3 100644 --- a/Assets/Darkmatter/Data/Drawings/Templates/Dog.asset +++ b/Assets/Darkmatter/Data/Drawings/Templates/Dog.asset @@ -17,7 +17,7 @@ MonoBehaviour: defaultThumbnail: {fileID: 21300000, guid: bcb7278db61b3ac458a7d0937be95114, type: 3} drawingPrefab: {fileID: 2095472511558828082, guid: fdaa71c7b745ae747a5cb2298b8457c6, type: 3} coloringPrefab: {fileID: 5797023492298654107, guid: 0a159cbe2a2712c4fa2ae4df463a1af1, type: 3} - completionAnimationPrefab: {fileID: 0} + completionAnimationPrefab: {fileID: 5081824796211567620, guid: c81d056e7a385406b90e6cb017db522d, type: 3} pieces: - {fileID: 11400000, guid: 4a67406eb6fe043628d2b6a4e0c970ba, type: 2} - {fileID: 11400000, guid: 4a67406eb6fe043628d2b6a4e0c970ba, type: 2} @@ -28,8 +28,6 @@ MonoBehaviour: - {fileID: 11400000, guid: 888b6a7cd3cae42099e8793f2e486dfd, type: 2} - {fileID: 11400000, guid: 888b6a7cd3cae42099e8793f2e486dfd, type: 2} - {fileID: 11400000, guid: 0caa62d6f271c4acb8a09a75ebcc708b, type: 2} - - {fileID: 11400000, guid: 0caa62d6f271c4acb8a09a75ebcc708b, type: 2} - - {fileID: 11400000, guid: 4a67406eb6fe043628d2b6a4e0c970ba, type: 2} regions: - RegionId: Body InitialColor: {r: 1, g: 1, b: 1, a: 1} diff --git a/Assets/Darkmatter/Data/Drawings/Templates/Earphone.asset b/Assets/Darkmatter/Data/Drawings/Templates/Earphone.asset index 8e8ae5f..b592929 100644 --- a/Assets/Darkmatter/Data/Drawings/Templates/Earphone.asset +++ b/Assets/Darkmatter/Data/Drawings/Templates/Earphone.asset @@ -17,7 +17,7 @@ MonoBehaviour: defaultThumbnail: {fileID: -174126971, guid: 788e2c50baa49594b82c67a97ec2f98d, type: 3} drawingPrefab: {fileID: 6408485857370138169, guid: 582c4d58f3b3cb445abe162dc1fa2792, type: 3} coloringPrefab: {fileID: 8794731807924147807, guid: 79087509e941a6d48ad227826bbeb307, type: 3} - completionAnimationPrefab: {fileID: 0} + completionAnimationPrefab: {fileID: 344719904930209396, guid: a8480f7fcc1444540bc3e3d04949f38f, type: 3} pieces: - {fileID: 11400000, guid: a3dc108a48b1e4f2196e8d49ae8e3edd, type: 2} - {fileID: 11400000, guid: 4a67406eb6fe043628d2b6a4e0c970ba, type: 2} diff --git a/Assets/Darkmatter/Data/Drawings/Templates/Envelop.asset b/Assets/Darkmatter/Data/Drawings/Templates/Envelop.asset index 8599b2c..b682eed 100644 --- a/Assets/Darkmatter/Data/Drawings/Templates/Envelop.asset +++ b/Assets/Darkmatter/Data/Drawings/Templates/Envelop.asset @@ -17,7 +17,7 @@ MonoBehaviour: defaultThumbnail: {fileID: -1212682616, guid: 62417922da5608742bec9efcc6e1edc8, type: 3} drawingPrefab: {fileID: 1138263911558588856, guid: bc8b3e8f6a3e016459b0bf73af697f86, type: 3} coloringPrefab: {fileID: 3274108684332002975, guid: 435e7cab757fe0743adb9b0e56047c84, type: 3} - completionAnimationPrefab: {fileID: 0} + completionAnimationPrefab: {fileID: 5676582392473424022, guid: 4b91156ff9f7c48458fe88411094873e, type: 3} pieces: - {fileID: 11400000, guid: 888b6a7cd3cae42099e8793f2e486dfd, type: 2} - {fileID: 11400000, guid: 4a67406eb6fe043628d2b6a4e0c970ba, type: 2} diff --git a/Assets/Darkmatter/Data/Drawings/Templates/Five.asset b/Assets/Darkmatter/Data/Drawings/Templates/Five.asset index a6c71ff..81f2468 100644 --- a/Assets/Darkmatter/Data/Drawings/Templates/Five.asset +++ b/Assets/Darkmatter/Data/Drawings/Templates/Five.asset @@ -17,7 +17,7 @@ MonoBehaviour: defaultThumbnail: {fileID: 1218086232, guid: 8932e7598fa18214ba0faeb3d4c43330, type: 3} drawingPrefab: {fileID: 8388886928725757613, guid: 03a73602b2a7a214fa8d84e4d6cdb0d9, type: 3} coloringPrefab: {fileID: 8803008988544010490, guid: e0c005e2ebec2554db1f36405cea88a8, type: 3} - completionAnimationPrefab: {fileID: 0} + completionAnimationPrefab: {fileID: 6408848241107625396, guid: 2e650c4d25ca048e5abdf8fbaeed6384, type: 3} pieces: - {fileID: 11400000, guid: 4a67406eb6fe043628d2b6a4e0c970ba, type: 2} - {fileID: 11400000, guid: 4a67406eb6fe043628d2b6a4e0c970ba, type: 2} diff --git a/Assets/Darkmatter/Scenes/Boot.unity b/Assets/Darkmatter/Scenes/Boot.unity index 5ba6864..23fb03e 100644 --- a/Assets/Darkmatter/Scenes/Boot.unity +++ b/Assets/Darkmatter/Scenes/Boot.unity @@ -1582,6 +1582,7 @@ Transform: - {fileID: 97140292} - {fileID: 978572232} - {fileID: 361052051} + - {fileID: 1707278033} m_Father: {fileID: 1798580248} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1239449674 @@ -1914,6 +1915,52 @@ MonoBehaviour: statusText: {fileID: 17632382} loadingSmoothTime: 10 dotInterval: 0.4 +--- !u!1 &1707278032 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1707278033} + - component: {fileID: 1707278034} + m_Layer: 0 + m_Name: AdServiceModule + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1707278033 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1707278032} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1050564725} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1707278034 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1707278032} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3a17cb41935543a6b4f67be8f398d774, type: 3} + m_Name: + m_EditorClassIdentifier: Services.Ads::Darkmatter.Services.Ads.AdServiceModule + adUnitCatalog: {fileID: 0} + adService: {fileID: 0} --- !u!1 &1740606684 GameObject: m_ObjectHideFlags: 0 @@ -2068,6 +2115,7 @@ MonoBehaviour: - {fileID: 789049883} - {fileID: 978572233} - {fileID: 361052052} + - {fileID: 1707278034} --- !u!1 &1890425864 GameObject: m_ObjectHideFlags: 0