com.amanotes.gdk 0.2.66 → 0.2.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/Editor/Extra/GDKAutoUpdateAdapter.cs +67 -0
  3. package/Editor/Extra/GDKAutoUpdateAdapter.cs.meta +11 -0
  4. package/Extra/AmaGDKInstaller.unitypackage +0 -0
  5. package/Extra/CheckDiskSpace.unitypackage +0 -0
  6. package/Extra/ForceUpdate.unitypackage +0 -0
  7. package/Extra/GoogleCMP.unitypackage +0 -0
  8. package/Extra/LegacyGDKUpdateHelper.unitypackage +0 -0
  9. package/Extra/LegacyGDKUpdateHelper.unitypackage.meta +7 -0
  10. package/Extra/PostProcessor.unitypackage +0 -0
  11. package/Packages/AmaGDKConfig.unitypackage +0 -0
  12. package/Packages/AmaGDKExample.unitypackage +0 -0
  13. package/Packages/AmaGDKTest.unitypackage +0 -0
  14. package/Packages/AppsFlyerAdapter.PurchaseConnector.unitypackage +0 -0
  15. package/Packages/AppsFlyerAdapter.unitypackage +0 -0
  16. package/Packages/FirebaseAnalyticsAdapter.unitypackage +0 -0
  17. package/Packages/FirebaseRemoteConfigAdapter.unitypackage +0 -0
  18. package/Packages/IronSourceAdapter.unitypackage +0 -0
  19. package/Packages/RevenueCatAdapter.unitypackage +0 -0
  20. package/Packages/SqliteAnalyticsAdapter.unitypackage +0 -0
  21. package/Runtime/Ad/AdExtension.cs +111 -0
  22. package/Runtime/Ad/AdExtension.cs.meta +3 -0
  23. package/Runtime/Ad/AdLogic.cs +530 -0
  24. package/Runtime/Ad/AdLogic.cs.meta +3 -0
  25. package/Runtime/Ad/AdModuleConfig.cs +39 -0
  26. package/Runtime/Ad/AdModuleConfig.cs.meta +3 -0
  27. package/Runtime/Ad/AdShowContext.cs +43 -0
  28. package/Runtime/Ad/AdShowContext.cs.meta +3 -0
  29. package/Runtime/Ad/AmaGDK.Ads.cs +383 -0
  30. package/Runtime/Ad.meta +8 -0
  31. package/Runtime/AmaGDK.Analytics.cs +20 -1
  32. package/Runtime/AmaGDK.Device.cs +105 -0
  33. package/Runtime/AmaGDK.Device.cs.meta +3 -0
  34. package/Runtime/AmaGDK.Mono.cs +0 -1
  35. package/Runtime/AmaGDK.cs +1 -1
  36. package/Runtime/Fps/AmaFPS.Utils.cs +44 -0
  37. package/Runtime/Fps/AmaFPS.Utils.cs.meta +3 -0
  38. package/Runtime/Fps/AmaFPS.cs +197 -0
  39. package/Runtime/Fps/AmaFPS.cs.meta +11 -0
  40. package/Runtime/Fps/AmaFPSVisualizer.cs +246 -0
  41. package/Runtime/Fps/AmaFPSVisualizer.cs.meta +11 -0
  42. package/Runtime/Fps/BollingerBands.cs +99 -0
  43. package/Runtime/Fps/BollingerBands.cs.meta +11 -0
  44. package/Runtime/Fps/FPSVisualizer.prefab +406 -0
  45. package/Runtime/Fps/FPSVisualizer.prefab.meta +7 -0
  46. package/Runtime/Fps/FrameRecorder.cs +172 -0
  47. package/Runtime/Fps/FrameRecorder.cs.meta +3 -0
  48. package/Runtime/Fps.meta +8 -0
  49. package/package.json +1 -1
  50. package/Runtime/AmaGDK.Ads.cs +0 -1077
  51. /package/Runtime/{AmaGDK.Ads.cs.meta → Ad/AmaGDK.Ads.cs.meta} +0 -0
@@ -1,1077 +0,0 @@
1
- using System;
2
- using System.Collections;
3
- using System.Collections.Generic;
4
- using UnityEngine;
5
- using Amanotes.Core.Internal;
6
-
7
- using static Amanotes.Core.Internal.Logging;
8
- using static Amanotes.Core.AmaGDK;
9
-
10
- namespace Amanotes.Core
11
- {
12
- public static class AdExtension
13
- {
14
- /// <summary>
15
- /// Invoke when ad view has opened
16
- /// </summary>
17
- public static IAdCallback OnAdOpened(this IAdCallback ad, Action callback)
18
- {
19
- if (!MakeSureAdNotNull(ad)) return null;
20
- Ads.context.onOpened -= callback;
21
- Ads.context.onOpened += callback;
22
- return ad;
23
- }
24
-
25
- /// <summary>
26
- /// The user finished watching the video, and should be rewarded.
27
- /// </summary>
28
- public static IAdCallback OnRewardReceived(this IAdCallback ad, Action callback)
29
- {
30
- if (!MakeSureAdNotNull(ad)) return null;
31
- Ads.context.onRewardReceived -= callback;
32
- Ads.context.onRewardReceived += callback;
33
- return ad;
34
- }
35
-
36
- /// <summary>
37
- /// Invoked when the video ad was clicked.
38
- /// </summary>
39
- public static IAdCallback OnAdClicked(this IAdCallback ad, Action callback)
40
- {
41
- if (!MakeSureAdNotNull(ad)) return null;
42
- Ads.context.onClicked -= callback;
43
- Ads.context.onClicked += callback;
44
- return ad;
45
- }
46
-
47
- /// <summary>
48
- /// Callback when the rewarded video ad was failed to show
49
- /// </summary>
50
- public static IAdCallback OnAdShowFailed(this IAdCallback ad, Action callback)
51
- {
52
- if (!MakeSureAdNotNull(ad)) return null;
53
- Ads.context.onShowFailed -= callback;
54
- Ads.context.onShowFailed += callback;
55
- return ad;
56
- }
57
-
58
- /// <summary>
59
- /// Invoked before OnAdOpened but is not reliable (not supported by all adNetworks)
60
- /// </summary>
61
- public static IAdCallback OnAdShowSuccess(this IAdCallback ad, Action callback)
62
- {
63
- if (!MakeSureAdNotNull(ad)) return null;
64
- Ads.context.onShowSuccess -= callback;
65
- Ads.context.onShowSuccess += callback;
66
- return ad;
67
- }
68
-
69
- /// <summary>
70
- /// Invoke when ad view is about to be closed
71
- /// </summary>
72
- public static IAdCallback OnAdClosed(this IAdCallback ad, Action callback)
73
- {
74
- if (!MakeSureAdNotNull(ad)) return null;
75
- Ads.context.onClosed -= callback;
76
- Ads.context.onClosed += callback;
77
- return ad;
78
- }
79
-
80
- /// <summary>
81
- /// This callback may invokes several times according to the AdShowReadyStatus
82
- /// - When there is no ad cached (wifi disabled / no internet / wait4Ad / timeout)
83
- /// - When the ad is cached & ready to show
84
- /// </summary>
85
- public static IAdCallback OnAdShowReadyStatus(this IAdCallback ad, Action<AdShowReadyStatus> callback)
86
- {
87
- if (!MakeSureAdNotNull(ad)) return null;
88
- Ads.context.onAdShowReadyStatus -= callback;
89
- Ads.context.onAdShowReadyStatus += callback;
90
- return ad;
91
- }
92
-
93
- /// <summary>
94
- /// The finalize callback that will always trigger to mark an end for the AdShowRoutine
95
- ///
96
- /// </summary>
97
- public static IAdCallback OnAdResult(this IAdCallback ad, Action<bool> callback)
98
- {
99
- if (!MakeSureAdNotNull(ad)) return null;
100
- Ads.context.onAdResult -= callback;
101
- Ads.context.onAdResult += callback;
102
- return ad;
103
- }
104
-
105
- /// <summary>
106
- /// Call right before the ad actually open (that means Ad has already been cached & available to show).
107
- /// This callback will not be triggered in case Ad is not available or no internet (in those case use OnAdShowReadyStatus callback)
108
- /// </summary>
109
- public static IAdCallback OnBeforeAdOpen(this IAdCallback ad, Action callback)
110
- {
111
- if (!MakeSureAdNotNull(ad)) return null;
112
- Ads.context.onBeforeAdOpen -= callback;
113
- Ads.context.onBeforeAdOpen += callback;
114
- return ad;
115
- }
116
-
117
- private static bool MakeSureAdNotNull(IAdCallback ad)
118
- {
119
- bool isValid = (ad != null);
120
- if (!isValid)
121
- {
122
- LogWarning("Something wrong:: no AdShowContext");
123
- }
124
- return isValid;
125
- }
126
- }
127
- public partial class AmaGDK // Ads module
128
- {
129
- partial class Event
130
- {
131
- public const string INTER_REQUEST = nameof(INTER_REQUEST);
132
- public const string INTER_SHOW_CALLED = nameof(INTER_SHOW_CALLED);
133
- public const string INTER_SHOW_READY = nameof(INTER_SHOW_READY);
134
- public const string INTER_SHOW_NOT_READY = nameof(INTER_SHOW_NOT_READY); // reason: string
135
- public const string INTER_SHOW_BEGIN = nameof(INTER_SHOW_BEGIN); // always call result: true / false
136
- public const string INTER_SHOW_END = nameof(INTER_SHOW_END); // always call result: true / false
137
-
138
- public const string REWARD_REQUEST = nameof(REWARD_REQUEST);
139
- public const string REWARD_VIDEO_SHOW_CALLED = nameof(REWARD_VIDEO_SHOW_CALLED);
140
- public const string REWARD_VIDEO_SHOW_READY = nameof(REWARD_VIDEO_SHOW_READY);
141
- public const string REWARD_VIDEO_SHOW_NOT_READY = nameof(REWARD_VIDEO_SHOW_NOT_READY); // reason: string
142
- // public const string REWARD_VIDEO_REWARD_GRANTED = nameof(REWARD_VIDEO_REWARD_GRANTED);
143
- public const string REWARD_VIDEO_SHOW_BEGIN = nameof(REWARD_VIDEO_SHOW_BEGIN); // always call result: true / false
144
- public const string REWARD_VIDEO_SHOW_END = nameof(REWARD_VIDEO_SHOW_END); // always call result: true / false
145
-
146
- public const string BANNER_SHOW = nameof(BANNER_SHOW);
147
- }
148
-
149
-
150
- [Serializable]
151
- internal class AdStat
152
- {
153
- // per session
154
- internal float prevCallTime;
155
- internal float currentCallTime;
156
- internal int callCount;
157
-
158
- internal float lastSuccessTime;
159
- internal int success;
160
- internal int failed;
161
-
162
- // persistent
163
- public int successTotal;
164
- public int failedTotal;
165
- }
166
-
167
- [Serializable]
168
- internal class AdsData : IJsonFile
169
- {
170
- public AdStat interstitial = new AdStat();
171
- public AdStat reward = new AdStat();
172
-
173
- internal AdStat GetStat(AdType adType)
174
- {
175
- return adType == AdType.Interstitial ? interstitial : reward;
176
- }
177
-
178
- internal int ShowCallCount(AdType adType)
179
- {
180
- return GetStat(adType).callCount;
181
- }
182
-
183
- internal int TimeSinceLastShowCalled(AdType adType)
184
- {
185
- AdStat stat = GetStat(adType);
186
- AdShowContext context = Ads.context;
187
-
188
- // Right inside XXX_ShowCalled() callbacks
189
- if (context != null && context.adType == adType)
190
- {
191
- if (stat.callCount == 1) return 0; // first call
192
- return (int)(stat.currentCallTime - stat.prevCallTime);
193
- }
194
-
195
- if (stat.callCount == 0) return 0; // not yet called
196
- return (int)(Time.realtimeSinceStartup - stat.prevCallTime);
197
- }
198
-
199
- internal int TimeSinceLastShowSuccess(AdType adType)
200
- {
201
- return (int)(Time.realtimeSinceStartup - GetStat(adType).lastSuccessTime);
202
- }
203
-
204
- internal void Save()
205
- {
206
- this.SaveJsonToFile();
207
- }
208
- }
209
-
210
- [Serializable]
211
- public class AdAdapterConfig
212
- {
213
-
214
- }
215
-
216
- public partial class Ads
217
- {
218
- public static bool allowAdRequest = true;
219
-
220
- // internal use
221
- internal static readonly AdsData localData = new AdsData().LoadJsonFromFile();
222
-
223
- internal protected static AdShowContext context;
224
- internal protected static AdAdapter _adapter;
225
- internal protected static float _savedVolume = -1;
226
- internal protected static float _savedTimeScale = -1;
227
-
228
- public static void OnInter_Request(Action callback)
229
- {
230
- dispatcher.AddListener(Event.INTER_REQUEST, callback);
231
- }
232
-
233
- public static void OnInter_ShowCalled(Action callback)
234
- {
235
- dispatcher.AddListener(Event.INTER_SHOW_CALLED, callback);
236
- }
237
-
238
- public static void OnReward_ShowCalled(Action callback)
239
- {
240
- dispatcher.AddListener(Event.REWARD_VIDEO_SHOW_CALLED, callback);
241
- }
242
-
243
- public static void OnInter_ShowReady(Action callback)
244
- {
245
- dispatcher.AddListener(Event.INTER_SHOW_READY, callback);
246
- }
247
-
248
- public static void OnReward_ShowReady(Action callback)
249
- {
250
- dispatcher.AddListener(Event.REWARD_VIDEO_SHOW_READY, callback);
251
- }
252
-
253
- public static void OnInter_ShowNotReady(Action<AdShowReadyStatus> callback)
254
- {
255
- dispatcher.AddListener(Event.INTER_SHOW_NOT_READY, callback);
256
- }
257
-
258
- public static void OnReward_ShowNotReady(Action<AdShowReadyStatus> callback)
259
- {
260
- dispatcher.AddListener(Event.REWARD_VIDEO_SHOW_NOT_READY, callback);
261
- }
262
- }
263
-
264
- public partial class Ads // Public
265
- {
266
- internal static bool InitModule()
267
- {
268
- _adapter = Adapter2.GetAdapter<AdAdapter>();
269
- return _adapter == null;
270
- }
271
-
272
- internal static void StartModule()
273
- {
274
- if (_adapter == null) return;
275
-
276
- if (Config.ad.enableInterstitial) _adapter.interstitial.StartLoadAd();
277
- if (Config.ad.enableRewarded) _adapter.rewardVideo.StartLoadAd();
278
- if (Config.ad.preloadBanner) PreloadBanner();
279
- if (_isBannerShowing)
280
- {
281
- _isBannerShowing = false;
282
- ShowBanner();
283
- }
284
- }
285
-
286
- public static bool HasInterstitial => _adapter?.interstitial.hasAd ?? false;
287
- public static bool HasRewardedVideo => _adapter?.rewardVideo.hasAd ?? false;
288
- public static bool IsBannerShowing => _isBannerShowing;
289
- public static bool IsAdShowing => context != null;
290
-
291
- private static bool ClearPrevContext()
292
- {
293
- if (context == null) return true;
294
- float duration = Time.realtimeSinceStartup - context.showCallAt;
295
- LogWarning($"[AD] ShowRequest IGNORED as another ad is showing (elapsedTime: {duration:n2}s):\n" + JsonUtility.ToJson(context, true));
296
- return false;
297
- }
298
-
299
- public static IAdCallback ShowInterstitial(string placementName = null, Dictionary<string, object> userData = null)
300
- {
301
- if (_adapter == null) return null;
302
- if (!ClearPrevContext()) return null;
303
-
304
- context = new AdShowContext(AdType.Interstitial, placementName, userData);
305
- _adapter.interstitial.StartShowAd();
306
- return context;
307
- }
308
-
309
- public static bool IsInterstitialShowing => (context != null) && (context.adType == AdType.Interstitial);
310
-
311
- public static IAdCallback ShowRewardedVideo(string placementName = null, Dictionary<string, object> userData = null)
312
- {
313
- if (_adapter == null) return null;
314
- if (!ClearPrevContext()) return null;
315
-
316
- context = new AdShowContext(AdType.VideoReward, placementName, userData);
317
- _adapter.rewardVideo.StartShowAd();
318
- return context;
319
- }
320
-
321
- public static bool IsRewardedVideoShowing => (context != null) && (context.adType == AdType.VideoReward);
322
-
323
-
324
- [NonSerialized] private static bool _isBannerShowing = false;
325
-
326
- public static void PreloadBanner()
327
- {
328
- if (!_config.ad.enableBanner)
329
- {
330
- LogWarning($"Banner not enabled! {_config.ad.enableBanner}");
331
- return;
332
- }
333
-
334
- if (_adapter == null)
335
- {
336
- LogWarning($"Adapter is null!");
337
- return;
338
- }
339
-
340
- if (_isBannerShowing)
341
- {
342
- LogWarning($"Banner is showing!");
343
- return;
344
- }
345
-
346
- _adapter.ShowBanner();
347
- _adapter.HideBanner();
348
- }
349
-
350
- public static void ShowBanner()
351
- {
352
- if (!_config.ad.enableBanner)
353
- {
354
- LogWarning($"Banner not enabled! {_config.ad.enableBanner}");
355
- return;
356
- }
357
-
358
- if (_isBannerShowing)
359
- {
360
- LogWarning($"Banner is showing!");
361
- return;
362
- }
363
-
364
- _isBannerShowing = true;
365
-
366
- if (_adapter == null)
367
- {
368
- LogWarning($"Adapter is null!");
369
- return;
370
- }
371
-
372
- dispatcher.Dispatch(Event.BANNER_SHOW);
373
- _adapter.ShowBanner();
374
- }
375
-
376
- public static void HideBanner()
377
- {
378
- if (!_config.ad.enableBanner) return;
379
- if (!_isBannerShowing) return;
380
- _isBannerShowing = false;
381
- if (_adapter == null) return;
382
- _adapter.HideBanner();
383
- }
384
-
385
- public static void StopWaitForAd()
386
- {
387
- if (_adapter == null) return;
388
- if (context == null)
389
- return;
390
-
391
- if (context.adType == AdType.Interstitial)
392
- _adapter.interstitial.StopShowAd();
393
- else
394
- _adapter.rewardVideo.StopShowAd();
395
- }
396
-
397
- /// <summary>
398
- /// Capping for interstitial ad
399
- /// - Time since last interstitial show success > interstitialCappingTime
400
- /// - Time since last rewardedVideo show success > rewardVideoCappingTime (for interstitial)
401
- /// </summary>
402
- /// <param name="interstitialCappingTime"></param>
403
- /// <param name="rewardedVideoCappingTime"></param>
404
- /// <returns></returns>
405
- public static bool IsCapped(float interstitialCappingTime = 0, float rewardedVideoCappingTime = 0)
406
- {
407
- bool interCapped = (interstitialCappingTime > 0) && TimeSinceLastInterstitialSucceed < interstitialCappingTime;
408
- bool rewardCapped = (rewardedVideoCappingTime > 0) && TimeSinceLastVideoRewardSucceed < rewardedVideoCappingTime;
409
- return interCapped || rewardCapped;
410
- }
411
-
412
- public static int TimeSinceLastInterstitialSucceed => localData.TimeSinceLastShowSuccess(AdType.Interstitial);
413
- public static int TimeSinceLastVideoRewardSucceed => localData.TimeSinceLastShowSuccess(AdType.VideoReward);
414
- public static int TimeSinceLastAdSucceed => Math.Min(TimeSinceLastInterstitialSucceed, TimeSinceLastVideoRewardSucceed);
415
- public static int TimeSinceLastInterstitialShowCalled => localData.TimeSinceLastShowCalled(AdType.Interstitial);
416
- public static int TimeSinceLastVideoRewardShowCalled => localData.TimeSinceLastShowCalled(AdType.VideoReward);
417
-
418
- public static int InterstitialShowCalledInSession => localData.ShowCallCount(AdType.Interstitial);
419
- public static int RewardVideoShowCalledInSession => localData.ShowCallCount(AdType.VideoReward);
420
-
421
- public static void SetUserId(string userId)
422
- {
423
- if (_adapter == null) return;
424
- _adapter.SetUserId(userId);
425
- }
426
- }
427
- }
428
- }
429
-
430
- namespace Amanotes.Core.Internal
431
- {
432
- [Serializable] public class AdModuleConfig
433
- {
434
- [Tooltip("Automatically retry requesting ad if an ad failed to response in this amount of time (in secs)")]
435
- public int adLoadTimeoutInSecs = 60;
436
-
437
- [Tooltip("When an ad is not ready to show, keep waiting for this amount of time (in secs)\n\nIf the ad is ready during that time, it would be shown normally.")]
438
- public int adShowTimeoutInSecs = 5;
439
-
440
- [Tooltip("When an ad is not ready to show, verify that there is an internet connection by ping the internet check URL .\nIf there is no internet connection, we will not need to wait for adShowTimeout secs")]
441
- public bool checkInternet = true;
442
-
443
- [NonSerialized] public bool enableInterstitial = true;
444
- [NonSerialized] public bool enableRewarded = true;
445
- [NonSerialized] public bool enableBanner = true;
446
-
447
- [Tooltip("Before showing an ad: set AudioListener.volume to 0\nAfter the ad is closed: restore the previously saved AudioListener.volume")]
448
- public bool autoMute = true;
449
-
450
- [Tooltip("Before showing an ad: set Time.timeScale to 0\nAfter the ad is closed: restore the previously saved Time.timeScale")]
451
- public bool autoTimeScale = true;
452
-
453
- [Tooltip("Preload banner right when Ad module init (default = false)")]
454
- public bool preloadBanner = false;
455
-
456
- [Header("EDITOR")]
457
- [Tooltip("Only applicable in Editor\n0 = 0% success\n1 = 100% success")]
458
- [Range(0f, 1f)] public float rewardAdShowSuccessRate = 1;
459
- }
460
-
461
- public partial class ConfigAsset
462
- {
463
- [SerializeField] public AdModuleConfig ad;
464
- }
465
-
466
- [Serializable] public abstract class AdAdapter : Adapter2
467
- {
468
- protected AdShowContext context => Ads.context;
469
- protected AdModuleConfig moduleConfig => Config.ad;
470
-
471
- // APIs
472
- internal protected abstract AdLogic interstitial { get; }
473
- internal protected abstract AdLogic rewardVideo { get; }
474
-
475
- public abstract void ShowBanner();
476
- public abstract void HideBanner();
477
-
478
- // Internally used
479
- internal protected abstract void SetUserId(string userId);
480
- }
481
-
482
- public interface IAdCallback { }
483
-
484
- public enum LoadAdsState
485
- {
486
- None,
487
- Requesting,
488
- Ready
489
- }
490
-
491
- public enum ShowAdsState
492
- {
493
- None,
494
- ShowCalled,
495
- WaitForAd,
496
- Showing,
497
- ShowFail,
498
- ShowSuccess
499
- }
500
-
501
- [Flags]
502
- public enum AdCallback
503
- {
504
- None = 0,
505
- ShowCalled = 1,
506
- ShowReadyStatus = 2,
507
- Open = 4,
508
- Reward = 8,
509
- Click = 16,
510
- Cancel = 32,
511
- Close = 64,
512
- Success = 128,
513
- Fail = 256
514
- }
515
-
516
- public enum AdType
517
- {
518
- Interstitial,
519
- VideoReward,
520
- Banner
521
- }
522
-
523
- public enum AdShowReadyStatus
524
- {
525
- None,
526
- Wifi3GDisabled,
527
- NoInternet,
528
- WaitForAd,
529
- TimeOut,
530
- Ready,
531
- }
532
-
533
- public class AdShowContext : IAdCallback
534
- {
535
- public readonly AdType adType;
536
- public readonly string placementName;
537
- public readonly Dictionary<string, object> userData;
538
- public AdCallback adCallback;
539
-
540
- internal Action onBeforeAdOpen;
541
- internal Action onOpened;
542
- internal Action onRewardReceived;
543
- internal Action onClicked;
544
- internal Action onShowSuccess;
545
- internal Action onShowFailed;
546
- internal Action onClosed;
547
- internal Action<AdShowReadyStatus> onAdShowReadyStatus;
548
- internal Action<bool> onAdResult;
549
-
550
- // Stats
551
- public float showCallAt;
552
- public float showFinishAt;
553
-
554
- public AdShowContext(AdType adType, string placementName, Dictionary<string, object> userData)
555
- {
556
- this.adType = adType;
557
- this.userData = userData;
558
- this.placementName = placementName;
559
- adCallback = AdCallback.None;
560
- showCallAt = Time.realtimeSinceStartup;
561
- showFinishAt = 0;
562
- }
563
-
564
- public bool hasFailedOrCancelled => (adCallback & (AdCallback.Fail | AdCallback.Cancel)) != 0;
565
- public bool potentiallyCompleted => (adCallback & (AdCallback.Close | AdCallback.Fail | AdCallback.Reward | AdCallback.Cancel)) != 0;
566
- public bool hasReward => (adCallback & AdCallback.Reward) != 0;
567
- public bool hasClosed => (adCallback & AdCallback.Close) != 0;
568
- public bool hasClicked => (adCallback & AdCallback.Click) != 0;
569
- }
570
-
571
- public abstract class AdLogic
572
- {
573
- protected AdModuleConfig adConfig => Config.ad;
574
- protected AdShowContext context => Ads.context;
575
-
576
- internal LoadAdsState _loadState = LoadAdsState.None;
577
- internal bool hasAd
578
- {
579
- get
580
- {
581
- if (_loadState == LoadAdsState.Ready && !isAdReady)
582
- {
583
- LogWarning("[Ad] Inconsistent Ready state (might caused by poor internet condition)");
584
- _loadState = LoadAdsState.None;
585
- StartLoadAd();
586
- }
587
-
588
- return _loadState == LoadAdsState.Ready;
589
- }
590
- }
591
-
592
- internal Coroutine _loadRoutine;
593
-
594
- public void StartLoadAd()
595
- {
596
- if (_loadState != LoadAdsState.None)
597
- {
598
- LogWarning("[Ad] StartLoadAd() --> Invalid state: " + _loadState);
599
- return;
600
- }
601
-
602
- Log("[Ad] StartLoadAd");
603
- _loadRoutine = _instance.StartCoroutine(LoadAdRoutine());
604
- }
605
-
606
- public void StopLoadAd()
607
- {
608
- Log("[Ad] StopLoadAd");
609
- if (_loadState == LoadAdsState.Requesting)
610
- {
611
- _loadState = LoadAdsState.None;
612
- }
613
-
614
- if (_loadRoutine == null) return;
615
- _instance.StopCoroutine(_loadRoutine);
616
- _loadRoutine = null;
617
- }
618
-
619
- IEnumerator LoadAdRoutine()
620
- {
621
- if (isAdReady)
622
- {
623
- Log("[Ad] LoadAdRoutine skipped because isAdReady = true!");
624
- _loadState = LoadAdsState.Ready;
625
- yield break;
626
- }
627
-
628
- var wait1Sec = new WaitForSecondsRealtime(1f);
629
- Log("[Ad] LoadAdRoutine start(): isAdReady = " + isAdReady);
630
- while (true)
631
- {
632
- yield return wait1Sec;
633
-
634
- if (!Ads.allowAdRequest)
635
- {
636
- Log("[Ad] LoadAdRoutine: allowAdRequest = false");
637
- continue;
638
- }
639
-
640
- if (!HasLocalNetworkConnection)
641
- {
642
- Log("[Ad] LoadAdRoutine: hasInternet = " + HasLocalNetworkConnection);
643
- continue;
644
- }
645
-
646
- _loadState = LoadAdsState.Requesting;
647
- _isRequesting = true;
648
- Log("[Ad] LoadAdRoutine: RequestAd()");
649
- RequestAd();
650
- dispatcher.Dispatch(
651
- _isInterstitial ? AmaGDK.Event.INTER_REQUEST : AmaGDK.Event.REWARD_REQUEST
652
- );
653
-
654
- int timeout = Config.ad.adLoadTimeoutInSecs;
655
- var counter = 0;
656
-
657
- while (counter < timeout || timeout == -1)
658
- {
659
- yield return wait1Sec;
660
- counter++;
661
- if (_isRequesting == false) break;
662
- }
663
-
664
- if (counter > timeout && timeout > 0) // timeout
665
- {
666
- Log("[Ad] LoadAdRoutine: RequestAd not responding (timeout) " + timeout + " secs");
667
- continue;
668
- }
669
-
670
- // request should be completed here!
671
- if (!isAdReady)
672
- {
673
- LogWarning($"[Ad] Request complete but failed! (load duration = {counter} secs)");
674
- continue;
675
- }
676
-
677
- _loadState = LoadAdsState.Ready;
678
- Log($"[Ad] LoadAdRoutine: Ad is ready! (load duration = {counter} secs)");
679
- yield break;
680
- }
681
- }
682
-
683
- bool HasLocalNetworkConnection => Application.internetReachability != NetworkReachability.NotReachable;
684
-
685
- // Override by actual Ad instance
686
- protected abstract AdType adType { get; }
687
- protected abstract bool isAdReady { get; }
688
- protected abstract void RequestAd();
689
- protected abstract void ShowAd();
690
-
691
- // Show Ad logic
692
- internal ShowAdsState _showState = ShowAdsState.None;
693
- private Coroutine _showAdRoutine;
694
- private bool _isRequesting;
695
- private bool _isInterstitial => adType == AdType.Interstitial;
696
-
697
- public void StartShowAd()
698
- {
699
- if (_showState != ShowAdsState.None)
700
- {
701
- LogWarning("[Ad] StartShowAd() --> Invalid _showState: " + _showState);
702
- }
703
-
704
- Log($"[Ad] {adType} StartShowAd");
705
- _showState = ShowAdsState.ShowCalled;
706
-
707
- AdStat stat = Ads.localData.GetStat(adType);
708
- stat.callCount++;
709
- stat.prevCallTime = stat.currentCallTime;
710
- stat.currentCallTime = Time.realtimeSinceStartup;
711
-
712
- dispatcher.Dispatch(
713
- _isInterstitial ? AmaGDK.Event.INTER_SHOW_CALLED : AmaGDK.Event.REWARD_VIDEO_SHOW_CALLED
714
- );
715
-
716
- if (_showAdRoutine != null) _instance.StopCoroutine(_showAdRoutine);
717
- _showAdRoutine = _instance.StartCoroutine(ShowAdRoutine());
718
- }
719
-
720
- public void StopShowAd()
721
- {
722
- Log($"[Ad] {adType} StopShowAd");
723
- _showState = ShowAdsState.None;
724
- if (_loadState == LoadAdsState.Ready && !isAdReady)
725
- {
726
- _loadState = LoadAdsState.None;
727
- StartLoadAd();
728
- }
729
-
730
- TriggerOnAfterAdShow();
731
- if (_showAdRoutine == null) return;
732
- _instance.StopCoroutine(_showAdRoutine);
733
- _showAdRoutine = null;
734
-
735
- if (Ads.context.adType == AdType.Interstitial)
736
- {
737
- ShowAdRoutineCompleted(!Ads.context.hasFailedOrCancelled);
738
- } else
739
- {
740
- ShowAdRoutineCompleted(Ads.context.hasReward);
741
- }
742
- }
743
-
744
- IEnumerator ShowAdRoutine()
745
- {
746
- // Wait to end frame so that all AdCallbacks finish registering
747
- yield return new WaitForEndOfFrame();
748
-
749
- // Wait for Ad
750
- if (!isAdReady)
751
- {
752
- if (_loadState == LoadAdsState.Ready)
753
- {
754
- LogWarning("[Ad] Inconsistent state report: isAdReady == false while _loadState == Ready");
755
- _loadState = LoadAdsState.None;
756
- }
757
-
758
- if (!HasLocalNetworkConnection)
759
- {
760
- _showState = ShowAdsState.ShowFail;
761
- OnAdShowReadyStatus(false, AdShowReadyStatus.Wifi3GDisabled);
762
- ShowAdRoutineCompleted(false);
763
- yield break;
764
- }
765
-
766
- int timeout = Config.ad.adShowTimeoutInSecs;
767
- if (timeout == 0) // do not wait for Ad
768
- {
769
- _showState = ShowAdsState.ShowFail;
770
- OnAdShowReadyStatus(false, AdShowReadyStatus.TimeOut);
771
- ShowAdRoutineCompleted(false);
772
- yield break;
773
- }
774
-
775
- _showState = ShowAdsState.WaitForAd;
776
- OnAdShowReadyStatus(false, AdShowReadyStatus.WaitForAd);
777
-
778
- if (_loadState != LoadAdsState.Requesting) StartLoadAd();
779
- var counter = 0;
780
- bool? hasInternet = null;
781
- if (adConfig.checkInternet) _instance.StartCoroutine(WebUtils.CheckInternet(result => hasInternet = result));
782
-
783
- var wait1Sec = new WaitForSecondsRealtime(1f);
784
- while (counter < timeout || timeout == -1)
785
- {
786
- yield return wait1Sec;
787
- counter++;
788
-
789
- // finish checking internet & result is false
790
- if (adConfig.checkInternet && hasInternet == false)
791
- {
792
- Log("[Ad] Stop WaitForAd : No internet!");
793
- _showState = ShowAdsState.ShowFail;
794
- OnAdShowReadyStatus(false, AdShowReadyStatus.NoInternet);
795
- ShowAdRoutineCompleted(false);
796
- yield break;
797
- }
798
-
799
- if (_loadState != LoadAdsState.Ready) continue;
800
- Log("[Ad] WaitForAd success after " + counter + " | timeout = " + timeout + " secs");
801
- break;
802
- }
803
-
804
- if (!isAdReady)
805
- {
806
- Log("[Ad] WaitForAd failed (timeout) " + counter + " | timeout = " + timeout + " secs");
807
- OnAdShowReadyStatus(false, AdShowReadyStatus.TimeOut);
808
- ShowAdRoutineCompleted(false);
809
- yield break;
810
- }
811
- }
812
-
813
- _showState = ShowAdsState.Showing;
814
- OnAdShowReadyStatus(true, AdShowReadyStatus.Ready);
815
- TriggerBeforeAdShow();
816
- ShowAd();
817
-
818
- while (!context.potentiallyCompleted)
819
- {
820
- yield return null; // callback as quickly as possible
821
- }
822
-
823
- if (adType == AdType.Interstitial)
824
- {
825
- ShowAdRoutineCompleted(!context.hasFailedOrCancelled);
826
- yield break;
827
- }
828
-
829
- if (context.hasFailedOrCancelled)
830
- {
831
- Log($"[Ad] {adType} Waiting for [close]");
832
- yield return null;
833
- ShowAdRoutineCompleted(false);
834
- yield break;
835
- }
836
-
837
- if (context.hasClosed)
838
- {
839
- // wait 1 frame in case hasReward callback after onClose
840
- if (!context.hasReward) yield return null;
841
- ShowAdRoutineCompleted(context.hasReward);
842
- yield break;
843
- }
844
-
845
- while (!context.hasClosed)
846
- {
847
- Log($"[Ad] {adType} Waiting for [close]");
848
- yield return null;
849
- }
850
-
851
- ShowAdRoutineCompleted(true);
852
- }
853
-
854
- private void ShowAdRoutineCompleted(bool isSuccess)
855
- {
856
- if (_loadState == LoadAdsState.Ready)
857
- {
858
- _loadState = isAdReady ? LoadAdsState.Ready : LoadAdsState.None;
859
- if (_loadState == LoadAdsState.None) StartLoadAd();
860
- }
861
-
862
- _showState = isSuccess ? ShowAdsState.ShowSuccess : ShowAdsState.ShowFail;
863
-
864
- // Extra callback
865
- Ads.context.showFinishAt = Time.realtimeSinceStartup;
866
- Ads.context.onAdResult?.Invoke(isSuccess);
867
-
868
- var localData = Ads.localData;
869
- var stat = _isInterstitial ? localData.interstitial : localData.reward;
870
- if (isSuccess)
871
- {
872
- stat.success++;
873
- stat.successTotal++;
874
- stat.lastSuccessTime = (int)Time.realtimeSinceStartup;
875
- } else
876
- {
877
- stat.failed++;
878
- stat.failedTotal++;
879
- }
880
-
881
- localData.Save();
882
- TriggerOnAfterAdShow();
883
-
884
- Log($"[Ad] {adType} ShowAdRoutineCompleted: {isSuccess}\n{JsonUtility.ToJson(Ads.context)}");
885
- Ads.context = null;
886
- _showState = ShowAdsState.None;
887
- }
888
-
889
- private void TriggerBeforeAdShow()
890
- {
891
- bool willSaveVolume = Config.ad.autoMute
892
- && AudioListener.volume > 0
893
- && Ads._savedVolume < 0;
894
-
895
- bool willSaveTimeScale = Config.ad.autoTimeScale
896
- && Time.timeScale > 0
897
- && Ads._savedTimeScale < 0;
898
-
899
- if (willSaveVolume)
900
- {
901
- Ads._savedVolume = AudioListener.volume;
902
- AudioListener.volume = 0;
903
- }
904
-
905
- if (willSaveTimeScale)
906
- {
907
- Ads._savedTimeScale = Time.timeScale;
908
- Time.timeScale = 0;
909
- }
910
-
911
- dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_BEGIN : AmaGDK.Event.REWARD_VIDEO_SHOW_BEGIN);
912
- Ads.context.onBeforeAdOpen?.Invoke();
913
- }
914
-
915
- private void TriggerOnAfterAdShow()
916
- {
917
- bool willRestoreVolume = Config.ad.autoMute
918
- && AudioListener.volume == 0
919
- && Ads._savedVolume > 0;
920
-
921
- bool willRestoreTimeScale = Config.ad.autoTimeScale
922
- && Time.timeScale == 0
923
- && Ads._savedTimeScale > 0;
924
-
925
- if (willRestoreVolume)
926
- {
927
- AudioListener.volume = Ads._savedVolume;
928
- Ads._savedVolume = -1;
929
- }
930
-
931
- if (willRestoreTimeScale)
932
- {
933
- Time.timeScale = Ads._savedTimeScale;
934
- Ads._savedTimeScale = -1;
935
- }
936
-
937
- bool isSuccess = _showState == ShowAdsState.ShowSuccess;
938
- dispatcher.Dispatch(_isInterstitial ? AmaGDK.Event.INTER_SHOW_END : AmaGDK.Event.REWARD_VIDEO_SHOW_END, isSuccess);
939
- }
940
-
941
- // Default implementation
942
- protected void OnAdClosed()
943
- {
944
- Log($"[Ad] {adType} OnAdClosed");
945
-
946
- if (Ads.context != null)
947
- {
948
- Ads.context.adCallback |= AdCallback.Close;
949
- Ads.context.onClosed?.Invoke();
950
- } else
951
- {
952
- LogWarning("[Ad] OnAdClosed() Something wrong - No AdContext");
953
- }
954
- }
955
-
956
- protected void OnAdClicked()
957
- {
958
- Log($"[Ad] {adType} OnAdClicked");
959
-
960
- if (Ads.context != null)
961
- {
962
- Ads.context.adCallback |= AdCallback.Click;
963
- Ads.context.onClicked?.Invoke();
964
- } else
965
- {
966
- LogWarning("[Ad] OnAdClicked() Something wrong - No AdContext");
967
- }
968
- }
969
-
970
- protected void OnAdShowFailed()
971
- {
972
- Log($"[Ad] {adType} OnAdShowFailed");
973
-
974
- // 509 Show Fail: No ads to show
975
- // 520 Show Fail: No internet connection; ShouldTrackNetworkState is enabled
976
- // 524 Show Fail: Placement %@ has reached its limit as defined per pace
977
- // 526 Show Fail: Ad unit has reached its daily cap per session
978
- // 1022 Show Fail: Cannot show an RV while another RV is showing
979
- // 1023 Show Fail: Show RV called when there are no available ads to show
980
- // 1036 Show Fail: Cannot show an while another is showing
981
-
982
- if (Ads.context != null)
983
- {
984
- Ads.context.adCallback |= AdCallback.Fail;
985
- Ads.context.onShowFailed?.Invoke();
986
- } else
987
- {
988
- LogWarning("[Ad] OnAdShowFailed() Something wrong - No AdContext");
989
- }
990
- }
991
-
992
- protected void OnAdShowSucceeded()
993
- {
994
- Log($"[Ad] {adType} OnAdShowSucceeded");
995
-
996
- if (Ads.context != null)
997
- {
998
- Ads.context.adCallback |= AdCallback.Success;
999
- Ads.context.onShowSuccess?.Invoke();
1000
- } else
1001
- {
1002
- LogWarning("[Ad] OnAdShowSucceeded() Something wrong - No AdContext");
1003
- }
1004
- }
1005
-
1006
- protected void OnAdShowReadyStatus(bool isReady, AdShowReadyStatus status)
1007
- {
1008
- if (Ads.context == null)
1009
- {
1010
- LogWarning("[Ad] OnAdOpen() Something wrong - No AdContext");
1011
- return;
1012
- }
1013
-
1014
- Ads.context.adCallback |= AdCallback.ShowReadyStatus;
1015
- Ads.context.onAdShowReadyStatus?.Invoke(status);
1016
- if (status == AdShowReadyStatus.Ready)
1017
- {
1018
- dispatcher.Dispatch(
1019
- _isInterstitial ? AmaGDK.Event.INTER_SHOW_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_READY
1020
- );
1021
- } else if (status == AdShowReadyStatus.NoInternet || status == AdShowReadyStatus.TimeOut || status == AdShowReadyStatus.Wifi3GDisabled)
1022
- {
1023
- dispatcher.Dispatch(
1024
- _isInterstitial ? AmaGDK.Event.INTER_SHOW_NOT_READY : AmaGDK.Event.REWARD_VIDEO_SHOW_NOT_READY,
1025
- status
1026
- );
1027
- }
1028
- }
1029
-
1030
- protected void OnAdOpen()
1031
- {
1032
- Log($"[Ad] {adType} OnAdOpen");
1033
-
1034
- if (Ads.context != null)
1035
- {
1036
- Ads.context.adCallback |= AdCallback.Open;
1037
- Ads.context.onOpened?.Invoke();
1038
- } else
1039
- {
1040
- LogWarning("[Ad] OnAdOpen() Something wrong - No AdContext");
1041
- }
1042
- }
1043
-
1044
- protected void OnAdReward()
1045
- {
1046
- Log($"[Ad] {adType} OnAdReward");
1047
-
1048
- if (Ads.context != null)
1049
- {
1050
- Ads.context.adCallback |= AdCallback.Reward;
1051
- Ads.context.onRewardReceived?.Invoke();
1052
- } else
1053
- {
1054
- LogWarning("[Ad] OnAdReward() Something wrong - No AdContext");
1055
- }
1056
- }
1057
-
1058
- protected void OnAdLoadSuccess()
1059
- {
1060
- Log($"[Ad] {adType} OnAdLoadSuccess");
1061
-
1062
- if (!_isRequesting && adType == AdType.Interstitial)
1063
- {
1064
- LogWarning("[Ad] Something wrong? OnAdReady called when no ad is loading! AdType=" + adType);
1065
- }
1066
-
1067
- _isRequesting = false;
1068
- }
1069
-
1070
-
1071
-
1072
- protected void OnAdLoadFailed(string error)
1073
- {
1074
- Log($"[Ad] {adType} OnAdLoadFailed: {error}");
1075
- }
1076
- }
1077
- }