com.amanotes.gdk 0.2.64 → 0.2.65-1
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.
- package/CHANGELOG.md +13 -0
- package/Extra/AmaGDKInstaller.unitypackage +0 -0
- package/Extra/CheckDiskSpace.unitypackage +0 -0
- package/Extra/ForceUpdate.unitypackage +0 -0
- package/Extra/GoogleCMP.unitypackage +0 -0
- package/Extra/GoogleCMP.unitypackage.meta +7 -0
- package/Extra/PostProcessor.unitypackage +0 -0
- package/Extra/SDKVersionTracking.unitypackage +0 -0
- package/Packages/AmaGDKConfig.unitypackage +0 -0
- package/Packages/AmaGDKExample.unitypackage +0 -0
- package/Packages/AmaGDKTest.unitypackage +0 -0
- package/Packages/AppsFlyerAdapter.PurchaseConnector.unitypackage +0 -0
- package/Packages/AppsFlyerAdapter.unitypackage +0 -0
- package/Packages/FirebaseAnalyticsAdapter.unitypackage +0 -0
- package/Packages/FirebaseRemoteConfigAdapter.unitypackage +0 -0
- package/Packages/IronSourceAdapter.unitypackage +0 -0
- package/Packages/RevenueCatAdapter.unitypackage +0 -0
- package/Packages/SqliteAnalyticsAdapter.unitypackage +0 -0
- package/Runtime/AmaGDK.Adapters.cs +1 -1
- package/Runtime/AmaGDK.Ads.cs +29 -2
- package/Runtime/AmaGDK.Analytics.cs +1 -2
- package/Runtime/AmaGDK.Mono.cs +111 -0
- package/Runtime/AmaGDK.Mono.cs.meta +3 -0
- package/Runtime/AmaGDK.Singleton.cs +27 -0
- package/Runtime/AmaGDK.Singleton.cs.meta +3 -0
- package/Runtime/AmaGDK.UserProfile.cs +1 -2
- package/Runtime/AmaGDK.cs +7 -55
- package/Runtime/Core/GDKRoutine.cs +61 -0
- package/Runtime/Core/GDKRoutine.cs.meta +3 -0
- package/Runtime/Core/GDKUnityCallback.cs +141 -0
- package/Runtime/Core/GDKUnityCallback.cs.meta +3 -0
- package/Runtime/Core.meta +8 -0
- package/Runtime/Internal/AmaGDK.Internal.cs +4 -8
- package/Runtime/Internal/AmaGDK.Utils.cs +2 -59
- package/Runtime/Klavar/Attributes/AccumulatedCountAttribute.cs +0 -1
- package/Runtime/Klavar/Attributes/MinMaxAttribute.cs +86 -79
- package/Runtime/Klavar/Attributes/MinMaxLengthAttribute.cs +47 -26
- package/Runtime/Klavar/Attributes/NotNullAttribute.cs +1 -1
- package/Runtime/Klavar/Attributes/RegexPatternAttribute.cs +10 -7
- package/Runtime/Klavar/Attributes/ToStringAttribute.cs +1 -1
- package/Runtime/Klavar/KlavarContainer.cs +21 -5
- package/Runtime/Klavar/KlavarEvent.cs +4 -1
- package/Runtime/Utils/GDKUtils.cs +35 -0
- package/Runtime/Utils/GDKUtils.cs.meta +3 -0
- package/Runtime/Utils.meta +8 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.66 - 2024-06-13]
|
|
4
|
+
- [Fix] Missing Google CMP in package release
|
|
5
|
+
|
|
6
|
+
## [0.2.65 - 2024-06-13]
|
|
7
|
+
- [Dev] Add GDKRoutine
|
|
8
|
+
- [Dev] Add option to preload banners
|
|
9
|
+
- [Fix] Handle GoogleCMP callback in main-thread
|
|
10
|
+
- Also: Ensure Logging.LogError is thead-safe
|
|
11
|
+
- [Fix] Manage banner status so not to request banner load multiple times
|
|
12
|
+
- [Add] GDKUnityCallback with thread-safe
|
|
13
|
+
- [Feature] Add fullads_impression & videoads_impression events for better fill rate tracking
|
|
14
|
+
- [Klavar] Improve parameter validation
|
|
15
|
+
|
|
3
16
|
## [0.2.64 - 2024-06-06]
|
|
4
17
|
- [Dev] Log gdk_init
|
|
5
18
|
- [Fix] map_user_id must contain FRB, AF, [GAID, IDFA]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/Runtime/AmaGDK.Ads.cs
CHANGED
|
@@ -275,7 +275,7 @@ namespace Amanotes.Core
|
|
|
275
275
|
|
|
276
276
|
if (Config.ad.enableInterstitial) _adapter.interstitial.StartLoadAd();
|
|
277
277
|
if (Config.ad.enableRewarded) _adapter.rewardVideo.StartLoadAd();
|
|
278
|
-
|
|
278
|
+
if (Config.ad.preloadBanner) PreloadBanner();
|
|
279
279
|
if (_isBannerShowing)
|
|
280
280
|
{
|
|
281
281
|
_isBannerShowing = false;
|
|
@@ -323,6 +323,30 @@ namespace Amanotes.Core
|
|
|
323
323
|
|
|
324
324
|
[NonSerialized] private static bool _isBannerShowing = false;
|
|
325
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
|
+
|
|
326
350
|
public static void ShowBanner()
|
|
327
351
|
{
|
|
328
352
|
if (!_config.ad.enableBanner)
|
|
@@ -426,6 +450,9 @@ namespace Amanotes.Core.Internal
|
|
|
426
450
|
[Tooltip("Before showing an ad: set Time.timeScale to 0\nAfter the ad is closed: restore the previously saved Time.timeScale")]
|
|
427
451
|
public bool autoTimeScale = true;
|
|
428
452
|
|
|
453
|
+
[Tooltip("Preload banner right when Ad module init (default = false)")]
|
|
454
|
+
public bool preloadBanner = false;
|
|
455
|
+
|
|
429
456
|
[Header("EDITOR")]
|
|
430
457
|
[Tooltip("Only applicable in Editor\n0 = 0% success\n1 = 100% success")]
|
|
431
458
|
[Range(0f, 1f)] public float rewardAdShowSuccessRate = 1;
|
|
@@ -444,7 +471,7 @@ namespace Amanotes.Core.Internal
|
|
|
444
471
|
// APIs
|
|
445
472
|
internal protected abstract AdLogic interstitial { get; }
|
|
446
473
|
internal protected abstract AdLogic rewardVideo { get; }
|
|
447
|
-
|
|
474
|
+
|
|
448
475
|
public abstract void ShowBanner();
|
|
449
476
|
public abstract void HideBanner();
|
|
450
477
|
|
|
@@ -343,8 +343,7 @@ namespace Amanotes.Core
|
|
|
343
343
|
// All adapters should be ready now!
|
|
344
344
|
|
|
345
345
|
// TODO: Refactor Resolve Early Calls
|
|
346
|
-
|
|
347
|
-
onFrameUpdate += ProcessEventQueue;
|
|
346
|
+
GDKUtils.OnFrameUpdate(ProcessEventQueue);
|
|
348
347
|
}
|
|
349
348
|
|
|
350
349
|
internal static EventParams PrepareEvent(string eventName)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
using Amanotes.Core.Internal;
|
|
2
|
+
using System;
|
|
3
|
+
using System.Collections;
|
|
4
|
+
using System.Collections.Generic;
|
|
5
|
+
using System.Threading;
|
|
6
|
+
using UnityEngine;
|
|
7
|
+
|
|
8
|
+
namespace Amanotes.Core
|
|
9
|
+
{
|
|
10
|
+
public partial class AmaGDK
|
|
11
|
+
{
|
|
12
|
+
internal static int mainThreadId = -1;
|
|
13
|
+
internal static readonly GDKUnityCallback unityCallbacks = new GDKUnityCallback();
|
|
14
|
+
|
|
15
|
+
internal static float realtimeSinceStartup;
|
|
16
|
+
internal static float time;
|
|
17
|
+
|
|
18
|
+
private void Update()
|
|
19
|
+
{
|
|
20
|
+
if (!isReady) return;
|
|
21
|
+
|
|
22
|
+
time = Time.time;
|
|
23
|
+
realtimeSinceStartup = Time.realtimeSinceStartup;
|
|
24
|
+
|
|
25
|
+
var cb = unityCallbacks;
|
|
26
|
+
cb.Invoke(ref cb.OnFrameUpdate);
|
|
27
|
+
cb.Invoke(ref cb.DoOnceNextFrame);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private void OnApplicationPause(bool pauseStatus)
|
|
31
|
+
{
|
|
32
|
+
var cb = unityCallbacks;
|
|
33
|
+
cb.Invoke(ref cb.OnApplicationPause, pauseStatus);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private void OnApplicationFocus(bool hasFocus)
|
|
37
|
+
{
|
|
38
|
+
var cb = unityCallbacks;
|
|
39
|
+
cb.Invoke(ref cb.OnApplicationFocus, hasFocus);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private void OnApplicationQuit()
|
|
43
|
+
{
|
|
44
|
+
var cb = unityCallbacks;
|
|
45
|
+
cb.Invoke(ref cb.OnApplicationQuit);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
namespace Amanotes.Core.Internal
|
|
51
|
+
{
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
public static partial class GDKUtils
|
|
55
|
+
{
|
|
56
|
+
public static bool isOnMainThread => Thread.CurrentThread.ManagedThreadId == AmaGDK.mainThreadId;
|
|
57
|
+
public static void DoOnMainThread(Action action)
|
|
58
|
+
{
|
|
59
|
+
if (isOnMainThread)
|
|
60
|
+
{
|
|
61
|
+
SafeInvoke(action);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
DoOnceNextFrame(action);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public static void OnFrameUpdate(Action action)
|
|
69
|
+
{
|
|
70
|
+
var cb = AmaGDK.unityCallbacks;
|
|
71
|
+
cb.AddCallback(ref cb.OnFrameUpdate, action);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public static void DoOnceNextFrame(Action action)
|
|
75
|
+
{
|
|
76
|
+
var cb = AmaGDK.unityCallbacks;
|
|
77
|
+
cb.AddCallback(ref cb.DoOnceNextFrame, action);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public static void DelayCall(float seconds, Action action)
|
|
81
|
+
{
|
|
82
|
+
DoOnMainThread(() => AmaGDK._instance.StartCoroutine(DelayCallRoutine(seconds, action)));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public static IEnumerator Timeout(float timeoutInSecs, Func<bool> completeCheckFunc)
|
|
86
|
+
{
|
|
87
|
+
float time = Time.realtimeSinceStartup;
|
|
88
|
+
while (completeCheckFunc() == false)
|
|
89
|
+
{
|
|
90
|
+
yield return null;
|
|
91
|
+
if (Time.realtimeSinceStartup - time > timeoutInSecs) yield break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private static IEnumerator DelayCallRoutine(float seconds, Action callback)
|
|
96
|
+
{
|
|
97
|
+
yield return new WaitForSecondsRealtime(seconds);
|
|
98
|
+
callback();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public static void AddUnityCallbacks<T>(T observer)
|
|
102
|
+
{
|
|
103
|
+
AmaGDK.unityCallbacks.AddObserver(observer);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public static void RemoveUnityCallbacks<T>(T observer)
|
|
107
|
+
{
|
|
108
|
+
AmaGDK.unityCallbacks.RemoveObserver(observer);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
using System.Threading;
|
|
3
|
+
using static Amanotes.Core.Internal.Logging;
|
|
4
|
+
using static Amanotes.Core.Internal.Messsage;
|
|
5
|
+
|
|
6
|
+
namespace Amanotes.Core
|
|
7
|
+
{
|
|
8
|
+
public partial class AmaGDK
|
|
9
|
+
{
|
|
10
|
+
internal static AmaGDK _instance;
|
|
11
|
+
|
|
12
|
+
private void Awake()
|
|
13
|
+
{
|
|
14
|
+
if (_instance != null)
|
|
15
|
+
{
|
|
16
|
+
LogWarning(MULTIPLE_INSTANCE);
|
|
17
|
+
Destroy(this);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_instance = this;
|
|
22
|
+
mainThreadId = Thread.CurrentThread.ManagedThreadId;
|
|
23
|
+
DontDestroyOnLoad(this);
|
|
24
|
+
StartCoroutine(InitRoutine());
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -326,8 +326,7 @@ namespace Amanotes.Core
|
|
|
326
326
|
// Always get the latest advertising id
|
|
327
327
|
GetAdvertisingId();
|
|
328
328
|
Logging.Log($"[UserProfile] user_id: {_userId}");
|
|
329
|
-
|
|
330
|
-
onFrameUpdate += SaveIfDirty;
|
|
329
|
+
GDKUtils.OnFrameUpdate(SaveIfDirty);
|
|
331
330
|
|
|
332
331
|
var adsId = Application.platform == RuntimePlatform.Android ? GAId : IDFA;
|
|
333
332
|
var delay = string.IsNullOrEmpty(AppsFlyerId)
|
package/Runtime/AmaGDK.cs
CHANGED
|
@@ -17,17 +17,16 @@ namespace Amanotes.Core
|
|
|
17
17
|
{
|
|
18
18
|
public partial class AmaGDK : MonoBehaviour
|
|
19
19
|
{
|
|
20
|
-
public const string VERSION = "0.2.
|
|
21
|
-
|
|
22
|
-
internal static AmaGDK _instance;
|
|
23
|
-
internal static bool _allowInit = false;
|
|
20
|
+
public const string VERSION = "0.2.66";
|
|
21
|
+
|
|
24
22
|
internal static Status _status = Status.None;
|
|
25
23
|
private static ConfigAsset _config = null;
|
|
26
24
|
internal static readonly GDKGeoLocation GeoLocation = new GDKGeoLocation();
|
|
27
25
|
internal static readonly GDKServerTime ServerTime = new GDKServerTime();
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
internal static bool _allowInit = false;
|
|
30
28
|
public bool autoInit = true;
|
|
29
|
+
|
|
31
30
|
internal static partial class Event
|
|
32
31
|
{
|
|
33
32
|
public const string GDK_HOOK_START = nameof(GDK_HOOK_START);
|
|
@@ -48,26 +47,6 @@ namespace Amanotes.Core
|
|
|
48
47
|
return _config;
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
|
-
|
|
52
|
-
private void Awake()
|
|
53
|
-
{
|
|
54
|
-
if (_instance != null)
|
|
55
|
-
{
|
|
56
|
-
if (_instance != this)
|
|
57
|
-
{
|
|
58
|
-
LogWarning(MULTIPLE_INSTANCE);
|
|
59
|
-
Destroy(this);
|
|
60
|
-
}
|
|
61
|
-
LogWarning("Should never be here!");
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
_instance = this;
|
|
66
|
-
DontDestroyOnLoad(this);
|
|
67
|
-
|
|
68
|
-
_allowInit = _allowInit || autoInit;
|
|
69
|
-
StartCoroutine(InitRoutine());
|
|
70
|
-
}
|
|
71
50
|
|
|
72
51
|
IEnumerator InitHook()
|
|
73
52
|
{
|
|
@@ -174,6 +153,8 @@ namespace Amanotes.Core
|
|
|
174
153
|
|
|
175
154
|
IEnumerator InitRoutine()
|
|
176
155
|
{
|
|
156
|
+
_allowInit = _allowInit || autoInit;
|
|
157
|
+
|
|
177
158
|
if (Config == null)
|
|
178
159
|
{
|
|
179
160
|
throw new Exception("[AmaGDK] " + CONFIG_NOT_FOUND);
|
|
@@ -357,35 +338,6 @@ namespace Amanotes.Core
|
|
|
357
338
|
public const string REVENUECAT = "RevenueCat";
|
|
358
339
|
}
|
|
359
340
|
}
|
|
360
|
-
|
|
361
|
-
public partial class AmaGDK
|
|
362
|
-
{
|
|
363
|
-
internal static event Action onFrameUpdate;
|
|
364
|
-
internal static event Action<bool> onApplicationPause;
|
|
365
|
-
internal static event Action<bool> applicationFocus;
|
|
366
|
-
internal static event Action applicationQuit;
|
|
367
|
-
|
|
368
|
-
private void OnApplicationPause(bool pauseStatus)
|
|
369
|
-
{
|
|
370
|
-
onApplicationPause?.Invoke(pauseStatus);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
private void OnApplicationFocus(bool hasFocus)
|
|
374
|
-
{
|
|
375
|
-
applicationFocus?.Invoke(hasFocus);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
private void Update()
|
|
379
|
-
{
|
|
380
|
-
if (!isReady) return;
|
|
381
|
-
onFrameUpdate?.Invoke();
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
private void OnApplicationQuit()
|
|
385
|
-
{
|
|
386
|
-
applicationQuit?.Invoke();
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
341
|
|
|
390
342
|
public partial class AmaGDK // Switch dev mode
|
|
391
343
|
{
|
|
@@ -499,7 +451,7 @@ namespace Amanotes.Core
|
|
|
499
451
|
{
|
|
500
452
|
if (completed)
|
|
501
453
|
{
|
|
502
|
-
LogWarning("
|
|
454
|
+
LogWarning("Add happen too late: Hook completed!");
|
|
503
455
|
return;
|
|
504
456
|
}
|
|
505
457
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections;
|
|
3
|
+
using UnityEngine;
|
|
4
|
+
namespace Amanotes.Core.Internal
|
|
5
|
+
{
|
|
6
|
+
[Flags]
|
|
7
|
+
internal enum RoutineStatus
|
|
8
|
+
{
|
|
9
|
+
None,
|
|
10
|
+
Started = 1,
|
|
11
|
+
Stopped = 2
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public class GDKRoutine
|
|
15
|
+
{
|
|
16
|
+
private RoutineStatus status;
|
|
17
|
+
private readonly IEnumerator action;
|
|
18
|
+
private Coroutine routine;
|
|
19
|
+
|
|
20
|
+
public bool isAlive => (status & RoutineStatus.Stopped) == 0;
|
|
21
|
+
|
|
22
|
+
public GDKRoutine(IEnumerator action)
|
|
23
|
+
{
|
|
24
|
+
this.action = action;
|
|
25
|
+
status = RoutineStatus.None;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public void StartRoutine()
|
|
29
|
+
{
|
|
30
|
+
if (!isAlive)
|
|
31
|
+
{
|
|
32
|
+
// StopRoutine() called before start: do nothing
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
status |= RoutineStatus.Started;
|
|
37
|
+
routine = AmaGDK._instance.StartCoroutine(action);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public void StopRoutine()
|
|
41
|
+
{
|
|
42
|
+
status |= RoutineStatus.Stopped;
|
|
43
|
+
if (routine != null) AmaGDK._instance.StopCoroutine(routine);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public static partial class GDKUtils
|
|
48
|
+
{
|
|
49
|
+
public static GDKRoutine StartCoroutine(IEnumerator action)
|
|
50
|
+
{
|
|
51
|
+
var routine = new GDKRoutine(action);
|
|
52
|
+
DoOnMainThread(routine.StartRoutine);
|
|
53
|
+
return routine;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public static void StopCoroutine(GDKRoutine gdkRoutine)
|
|
57
|
+
{
|
|
58
|
+
gdkRoutine.StopRoutine();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
|
|
3
|
+
namespace Amanotes.Core.Internal
|
|
4
|
+
{
|
|
5
|
+
public interface IOnApplicationPause { void OnApplicationPause(bool pauseStatus); }
|
|
6
|
+
public interface IOnApplicationQuit { void OnApplicationQuit(); }
|
|
7
|
+
public interface IOnApplicationFocus { void OnApplicationFocus(bool hasFocus); }
|
|
8
|
+
public interface IOnFrameUpdate { void OnFrameUpdate(); }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
namespace Amanotes.Core.Internal
|
|
12
|
+
{
|
|
13
|
+
public class GDKUnityCallback
|
|
14
|
+
{
|
|
15
|
+
public Action<bool> OnApplicationPause;
|
|
16
|
+
public Action<bool> OnApplicationFocus;
|
|
17
|
+
public Action OnApplicationQuit;
|
|
18
|
+
public Action OnFrameUpdate;
|
|
19
|
+
public Action DoOnceNextFrame;
|
|
20
|
+
|
|
21
|
+
// Lock object to ensure thread-safe operations
|
|
22
|
+
private readonly object _locker = new object();
|
|
23
|
+
|
|
24
|
+
// Add Listener
|
|
25
|
+
public void AddCallback(ref Action source, Action callback)
|
|
26
|
+
{
|
|
27
|
+
if (callback == null) return;
|
|
28
|
+
lock (_locker)
|
|
29
|
+
{
|
|
30
|
+
source -= callback;
|
|
31
|
+
source += callback;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
public void AddCallback<T>(ref Action<T> source, Action<T> callback)
|
|
35
|
+
{
|
|
36
|
+
if (callback == null) return;
|
|
37
|
+
lock (_locker)
|
|
38
|
+
{
|
|
39
|
+
source -= callback;
|
|
40
|
+
source += callback;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
// Remove Listener
|
|
46
|
+
public void RemoveCallback(ref Action source, Action callback)
|
|
47
|
+
{
|
|
48
|
+
if (callback == null) return;
|
|
49
|
+
lock (_locker)
|
|
50
|
+
{
|
|
51
|
+
source -= callback;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
public void RemoveCallback<T>(ref Action<T> source, Action<T> callback)
|
|
55
|
+
{
|
|
56
|
+
if (callback == null) return;
|
|
57
|
+
lock (_locker)
|
|
58
|
+
{
|
|
59
|
+
source -= callback;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
// Invoke
|
|
65
|
+
public void Invoke(ref Action source)
|
|
66
|
+
{
|
|
67
|
+
if (source == null) return;
|
|
68
|
+
Action actionsToInvoke;
|
|
69
|
+
lock (_locker)
|
|
70
|
+
{
|
|
71
|
+
bool remove = source == DoOnceNextFrame;
|
|
72
|
+
actionsToInvoke = source;
|
|
73
|
+
if (remove) source = null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
GDKUtils.SafeInvoke(actionsToInvoke);
|
|
77
|
+
}
|
|
78
|
+
public void Invoke<T>(ref Action<T> source, T data)
|
|
79
|
+
{
|
|
80
|
+
if (source == null) return;
|
|
81
|
+
Action<T> actionsToInvoke;
|
|
82
|
+
lock (_locker)
|
|
83
|
+
{
|
|
84
|
+
actionsToInvoke = source;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
GDKUtils.SafeInvoke(actionsToInvoke, data);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
// Observer
|
|
92
|
+
public void AddObserver<T>(T observer)
|
|
93
|
+
{
|
|
94
|
+
if (observer == null) return;
|
|
95
|
+
|
|
96
|
+
if (observer is IOnFrameUpdate u)
|
|
97
|
+
{
|
|
98
|
+
AddCallback(ref OnFrameUpdate, u.OnFrameUpdate);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (observer is IOnApplicationPause p)
|
|
102
|
+
{
|
|
103
|
+
AddCallback(ref OnApplicationPause, p.OnApplicationPause);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (observer is IOnApplicationFocus f)
|
|
107
|
+
{
|
|
108
|
+
AddCallback(ref OnApplicationFocus, f.OnApplicationFocus);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (observer is IOnApplicationQuit q)
|
|
112
|
+
{
|
|
113
|
+
AddCallback(ref OnApplicationQuit, q.OnApplicationQuit);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
public void RemoveObserver<T>(T observer)
|
|
117
|
+
{
|
|
118
|
+
if (observer == null) return;
|
|
119
|
+
|
|
120
|
+
if (observer is IOnFrameUpdate u)
|
|
121
|
+
{
|
|
122
|
+
RemoveCallback(ref OnFrameUpdate, u.OnFrameUpdate);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (observer is IOnApplicationPause p)
|
|
126
|
+
{
|
|
127
|
+
RemoveCallback(ref OnApplicationPause, p.OnApplicationPause);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (observer is IOnApplicationFocus f)
|
|
131
|
+
{
|
|
132
|
+
RemoveCallback(ref OnApplicationFocus, f.OnApplicationFocus);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (observer is IOnApplicationQuit q)
|
|
136
|
+
{
|
|
137
|
+
RemoveCallback(ref OnApplicationQuit, q.OnApplicationQuit);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -87,12 +87,13 @@ namespace Amanotes.Core.Internal
|
|
|
87
87
|
public static void LogError(string message)
|
|
88
88
|
{
|
|
89
89
|
if (Config.common.logLevel >= LogLevel.Error) Debug.LogError($"AmaGDK {message}");
|
|
90
|
-
if (logNonfatalErrorHook
|
|
90
|
+
if (logNonfatalErrorHook == null) return;
|
|
91
|
+
GDKUtils.DoOnMainThread(() =>
|
|
91
92
|
{
|
|
92
93
|
if (nonFatalDict.Contains(message)) return; // LogOnce
|
|
93
94
|
nonFatalDict.Add(message);
|
|
94
|
-
logNonfatalErrorHook(message);
|
|
95
|
-
}
|
|
95
|
+
logNonfatalErrorHook(message);
|
|
96
|
+
});
|
|
96
97
|
}
|
|
97
98
|
public static void Log(string message)
|
|
98
99
|
{
|
|
@@ -184,11 +185,6 @@ namespace Amanotes.Core.Internal
|
|
|
184
185
|
}
|
|
185
186
|
}
|
|
186
187
|
|
|
187
|
-
public interface IOnApplicationPause { void OnApplicationPause(bool pauseStatus); }
|
|
188
|
-
public interface IOnApplicationQuit { void OnApplicationQuit(); }
|
|
189
|
-
public interface IOnApplicationFocus { void OnApplicationFocus(bool hasFocus); }
|
|
190
|
-
public interface IOnFrameUpdate { void OnFrameUpdate(); }
|
|
191
|
-
|
|
192
188
|
public static class Utils // Hidden Utils
|
|
193
189
|
{
|
|
194
190
|
private static readonly Dictionary<string, float> LastFireInSessions = new Dictionary<string, float>();
|
|
@@ -12,65 +12,8 @@ using static Amanotes.Core.Internal.Logging;
|
|
|
12
12
|
|
|
13
13
|
namespace Amanotes.Core.Internal
|
|
14
14
|
{
|
|
15
|
-
public static class GDKUtils
|
|
15
|
+
public static partial class GDKUtils
|
|
16
16
|
{
|
|
17
|
-
public static void StartCoroutine(IEnumerator action)
|
|
18
|
-
{
|
|
19
|
-
AmaGDK._instance.StartCoroutine(action);
|
|
20
|
-
}
|
|
21
|
-
public static void DelayCall(float seconds, Action action)
|
|
22
|
-
{
|
|
23
|
-
AmaGDK._instance.StartCoroutine(DelayCallRoutine(seconds, action));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public static void RegisterUnityCallbacks<T>(T target)
|
|
27
|
-
{
|
|
28
|
-
if (target == null)
|
|
29
|
-
{
|
|
30
|
-
LogWarning("RegisterUnityCallbacks: Target is null!");
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (target is IOnFrameUpdate u)
|
|
35
|
-
{
|
|
36
|
-
AmaGDK.onFrameUpdate -= u.OnFrameUpdate;
|
|
37
|
-
AmaGDK.onFrameUpdate += u.OnFrameUpdate;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (target is IOnApplicationPause p)
|
|
41
|
-
{
|
|
42
|
-
AmaGDK.onApplicationPause -= p.OnApplicationPause;
|
|
43
|
-
AmaGDK.onApplicationPause += p.OnApplicationPause;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (target is IOnApplicationFocus f)
|
|
47
|
-
{
|
|
48
|
-
AmaGDK.applicationFocus -= f.OnApplicationFocus;
|
|
49
|
-
AmaGDK.applicationFocus += f.OnApplicationFocus;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (target is IOnApplicationQuit q)
|
|
53
|
-
{
|
|
54
|
-
AmaGDK.applicationQuit -= q.OnApplicationQuit;
|
|
55
|
-
AmaGDK.applicationQuit += q.OnApplicationQuit;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
private static IEnumerator DelayCallRoutine(float seconds, Action callback)
|
|
60
|
-
{
|
|
61
|
-
yield return new WaitForSecondsRealtime(seconds);
|
|
62
|
-
callback();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
public static IEnumerator Timeout(float timeoutInSecs, Func<bool> completeCheckFunc)
|
|
66
|
-
{
|
|
67
|
-
float time = Time.realtimeSinceStartup;
|
|
68
|
-
while (completeCheckFunc() == false)
|
|
69
|
-
{
|
|
70
|
-
yield return null;
|
|
71
|
-
if (Time.realtimeSinceStartup - time > timeoutInSecs) yield break;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
17
|
|
|
75
18
|
|
|
76
19
|
public static bool IsFromTemplate(string formattedString, string template)
|
|
@@ -157,7 +100,7 @@ namespace Amanotes.Core.Internal
|
|
|
157
100
|
segments[matches.Count] = template.Substring(lastIndex);
|
|
158
101
|
return segments;
|
|
159
102
|
}
|
|
160
|
-
|
|
103
|
+
|
|
161
104
|
internal static void ThrowIf(bool condition, string message)
|
|
162
105
|
{
|
|
163
106
|
if (condition)
|
|
@@ -1,128 +1,135 @@
|
|
|
1
1
|
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
2
3
|
using System.Reflection;
|
|
3
4
|
|
|
4
5
|
namespace Amanotes.Core
|
|
5
6
|
{
|
|
7
|
+
|
|
8
|
+
internal static class NumericValidationHelper
|
|
9
|
+
{
|
|
10
|
+
private static readonly HashSet<Type> NumericTypes = new HashSet<Type> { typeof(int), typeof(float), typeof(double) };
|
|
11
|
+
|
|
12
|
+
internal static bool IsNumeric(this object param)
|
|
13
|
+
{
|
|
14
|
+
return NumericTypes.Contains(param.GetType());
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
6
18
|
/// <summary>
|
|
7
19
|
/// Min, Max validate param
|
|
8
20
|
/// </summary>
|
|
9
21
|
public class MinMaxAttribute : ValidateLogEventAttribute
|
|
10
22
|
{
|
|
23
|
+
private readonly double min;
|
|
24
|
+
private readonly double max;
|
|
25
|
+
private readonly bool inclusiveMin;
|
|
26
|
+
private readonly bool inclusiveMax;
|
|
11
27
|
|
|
12
|
-
public
|
|
13
|
-
|
|
14
|
-
public readonly double max;
|
|
15
|
-
|
|
16
|
-
public MinMaxAttribute(double min, double max)
|
|
28
|
+
public MinMaxAttribute(double min, double max, bool inclusiveMin = true, bool inclusiveMax = true)
|
|
17
29
|
{
|
|
18
30
|
this.min = min;
|
|
19
31
|
this.max = max;
|
|
32
|
+
this.inclusiveMin = inclusiveMin;
|
|
33
|
+
this.inclusiveMax = inclusiveMax;
|
|
20
34
|
}
|
|
21
35
|
|
|
22
|
-
|
|
23
36
|
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
24
37
|
{
|
|
25
|
-
if (
|
|
26
|
-
|
|
38
|
+
if (param == null)
|
|
39
|
+
{
|
|
40
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must not be null.");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!param.IsNumeric())
|
|
45
|
+
{
|
|
46
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Type of '{fieldInfo.Name}' must be int, float, or double.");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
27
49
|
|
|
28
50
|
double val = Convert.ToDouble(param);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
public class MinimumAttribute : ValidateLogEventAttribute
|
|
36
|
-
{
|
|
51
|
+
bool isMinValid = inclusiveMin ? val >= min : val > min;
|
|
52
|
+
bool isMaxValid = inclusiveMax ? val <= max : val < max;
|
|
37
53
|
|
|
38
|
-
|
|
54
|
+
if (isMinValid && isMaxValid) return;
|
|
39
55
|
|
|
56
|
+
string minBracket = inclusiveMin ? "[" : "(";
|
|
57
|
+
string maxBracket = inclusiveMax ? "]" : ")";
|
|
58
|
+
string rangeDescription = $"{minBracket}{min}, {max}{maxBracket}";
|
|
40
59
|
|
|
41
|
-
|
|
42
|
-
{
|
|
43
|
-
this.min = min;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
48
|
-
{
|
|
49
|
-
if (!(param is int) && !(param is float) && !(param is double))
|
|
50
|
-
throw new ArgumentException($"type of `{fieldInfo.Name}` is must be int, float or double");
|
|
51
|
-
|
|
52
|
-
double val = Convert.ToDouble(param);
|
|
53
|
-
if (val < min) throw new ArgumentException($"Field `{fieldInfo.Name}` must be greater or equal to {min}. Current value: {param}");
|
|
60
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must be in the {rangeDescription}. Current value: {param}");
|
|
54
61
|
}
|
|
55
62
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
public class ExclusiveMinimumAttribute : ValidateLogEventAttribute
|
|
63
|
+
|
|
64
|
+
public class MinimumAttribute : ValidateLogEventAttribute
|
|
59
65
|
{
|
|
66
|
+
private readonly double min;
|
|
67
|
+
private readonly bool inclusive;
|
|
60
68
|
|
|
61
|
-
public
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
public ExclusiveMinimumAttribute(double min)
|
|
69
|
+
public MinimumAttribute(double min, bool inclusive = true)
|
|
65
70
|
{
|
|
66
71
|
this.min = min;
|
|
72
|
+
this.inclusive = inclusive;
|
|
67
73
|
}
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
|
|
70
75
|
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
71
76
|
{
|
|
72
|
-
if (
|
|
73
|
-
|
|
77
|
+
if (param == null)
|
|
78
|
+
{
|
|
79
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must not be null.");
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!param.IsNumeric())
|
|
83
|
+
{
|
|
84
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Type of '{fieldInfo.Name}' must be int, float, or double.");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
74
87
|
|
|
75
88
|
double val = Convert.ToDouble(param);
|
|
76
|
-
if (
|
|
89
|
+
if (inclusive)
|
|
90
|
+
{
|
|
91
|
+
if (val < min) KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must be greater than or equal to {min}. Current value: {param}");
|
|
92
|
+
}
|
|
93
|
+
else
|
|
94
|
+
{
|
|
95
|
+
if (val <= min) KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must be greater than {min}. Current value: {param}");
|
|
96
|
+
}
|
|
77
97
|
}
|
|
78
98
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
99
|
+
|
|
84
100
|
public class MaximumAttribute : ValidateLogEventAttribute
|
|
85
101
|
{
|
|
102
|
+
private readonly double max;
|
|
103
|
+
private readonly bool inclusive;
|
|
86
104
|
|
|
87
|
-
public
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
public MaximumAttribute(double max)
|
|
91
|
-
{
|
|
92
|
-
this.max = max;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
97
|
-
{
|
|
98
|
-
if (!(param is int) && !(param is float) && !(param is double))
|
|
99
|
-
throw new ArgumentException($"type of `{fieldInfo.Name}` is must be int, float or double");
|
|
100
|
-
|
|
101
|
-
double val = Convert.ToDouble(param);
|
|
102
|
-
if (val > max) throw new ArgumentException($"Field `{fieldInfo.Name}` must be smaller or equal to {max}. Current value: {param}");
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
public class ExclusiveMaximumAttribute : ValidateLogEventAttribute
|
|
108
|
-
{
|
|
109
|
-
|
|
110
|
-
public readonly double max;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
public ExclusiveMaximumAttribute(double max)
|
|
105
|
+
public MaximumAttribute(double max, bool inclusive = true)
|
|
114
106
|
{
|
|
115
107
|
this.max = max;
|
|
108
|
+
this.inclusive = inclusive;
|
|
116
109
|
}
|
|
117
|
-
|
|
118
|
-
|
|
110
|
+
|
|
119
111
|
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
120
112
|
{
|
|
121
|
-
if (
|
|
122
|
-
|
|
113
|
+
if (param == null)
|
|
114
|
+
{
|
|
115
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must not be null.");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (!param.IsNumeric())
|
|
119
|
+
{
|
|
120
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Type of '{fieldInfo.Name}' must be int, float, or double.");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
123
|
|
|
124
124
|
double val = Convert.ToDouble(param);
|
|
125
|
-
if (
|
|
125
|
+
if (inclusive)
|
|
126
|
+
{
|
|
127
|
+
if (val > max) KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must be less than or equal to {max}. Current value: {param}");
|
|
128
|
+
}
|
|
129
|
+
else
|
|
130
|
+
{
|
|
131
|
+
if (val >= max) KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must be less than {max}. Current value: {param}");
|
|
132
|
+
}
|
|
126
133
|
}
|
|
127
134
|
}
|
|
128
135
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
using System;
|
|
2
1
|
using System.Reflection;
|
|
3
2
|
|
|
4
3
|
namespace Amanotes.Core
|
|
5
4
|
{
|
|
5
|
+
|
|
6
6
|
/// <summary>
|
|
7
7
|
/// Min, Max length valudate validate param. (Just apply for string only)
|
|
8
8
|
/// </summary>
|
|
9
9
|
public class MinMaxLengthAttribute : ValidateLogEventAttribute
|
|
10
10
|
{
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
private readonly int min;
|
|
12
|
+
private readonly int max;
|
|
13
13
|
|
|
14
14
|
public MinMaxLengthAttribute(int min, int max)
|
|
15
15
|
{
|
|
@@ -17,58 +17,74 @@ namespace Amanotes.Core
|
|
|
17
17
|
this.max = max;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
21
20
|
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
22
21
|
{
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
if (param is string text)
|
|
23
|
+
{
|
|
24
|
+
if (text.Length >= min && text.Length <= max) return;
|
|
25
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"The length of string field '{fieldInfo.Name}' must be between {min} and {max} (inclusive). Current length: {text.Length}");
|
|
26
|
+
}
|
|
27
|
+
else
|
|
28
|
+
{
|
|
29
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, param is null ? $"Field {fieldInfo.Name} must not be null." : $"Field {fieldInfo.Name} must be a string.");
|
|
30
|
+
}
|
|
27
31
|
}
|
|
28
32
|
}
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
|
|
31
34
|
public class MinLengthAttribute : ValidateLogEventAttribute
|
|
32
35
|
{
|
|
33
|
-
|
|
36
|
+
private readonly int min;
|
|
34
37
|
|
|
35
38
|
public MinLengthAttribute(int min)
|
|
36
39
|
{
|
|
37
40
|
this.min = min;
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
|
|
41
43
|
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
42
44
|
{
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
if (param is string text)
|
|
46
|
+
{
|
|
47
|
+
if (text.Length < min)
|
|
48
|
+
{
|
|
49
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"The length of string field '{fieldInfo.Name}' must be greater than or equal to {min}. Current length: {text.Length}");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else
|
|
53
|
+
{
|
|
54
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, param is null ? $"Field {fieldInfo.Name} must not be null." : $"Field {fieldInfo.Name} must be a string.");
|
|
55
|
+
}
|
|
46
56
|
}
|
|
47
57
|
}
|
|
48
58
|
|
|
49
|
-
|
|
50
59
|
public class MaxLengthAttribute : ValidateLogEventAttribute
|
|
51
60
|
{
|
|
52
|
-
|
|
61
|
+
private readonly int max;
|
|
53
62
|
|
|
54
63
|
public MaxLengthAttribute(int max)
|
|
55
64
|
{
|
|
56
65
|
this.max = max;
|
|
57
66
|
}
|
|
58
67
|
|
|
59
|
-
|
|
60
68
|
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
61
69
|
{
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
if (param is string text)
|
|
71
|
+
{
|
|
72
|
+
if (text.Length > max)
|
|
73
|
+
{
|
|
74
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"The length of string field '{fieldInfo.Name}' must be less than or equal to {max}. Current length: {text.Length}");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else
|
|
78
|
+
{
|
|
79
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, param is null ? $"Field {fieldInfo.Name} must not be null." : $"Field {fieldInfo.Name} must be a string.");
|
|
80
|
+
}
|
|
65
81
|
}
|
|
66
82
|
}
|
|
67
83
|
|
|
68
84
|
|
|
69
85
|
public class FixedLengthAttribute : ValidateLogEventAttribute
|
|
70
86
|
{
|
|
71
|
-
|
|
87
|
+
private readonly int length;
|
|
72
88
|
|
|
73
89
|
public FixedLengthAttribute(int length)
|
|
74
90
|
{
|
|
@@ -77,10 +93,15 @@ namespace Amanotes.Core
|
|
|
77
93
|
|
|
78
94
|
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
79
95
|
{
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
96
|
+
if (param is string text)
|
|
97
|
+
{
|
|
98
|
+
if (text.Length != length)
|
|
99
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo,$"The length of string field '{fieldInfo.Name}' must be equal to {length}. Current length: {text.Length}");
|
|
100
|
+
}
|
|
101
|
+
else
|
|
102
|
+
{
|
|
103
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, param is null ? $"Field {fieldInfo.Name} must not be null." : $"Field {fieldInfo.Name} must be string.");
|
|
104
|
+
}
|
|
84
105
|
}
|
|
85
106
|
}
|
|
86
107
|
}
|
|
@@ -10,7 +10,7 @@ namespace Amanotes.Core
|
|
|
10
10
|
{
|
|
11
11
|
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
12
12
|
{
|
|
13
|
-
if (param is null)
|
|
13
|
+
if (param is null) KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must not be null");
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
using System;
|
|
2
|
+
using System.Globalization;
|
|
2
3
|
using System.Reflection;
|
|
3
4
|
using System.Text.RegularExpressions;
|
|
4
5
|
|
|
@@ -18,23 +19,25 @@ namespace Amanotes.Core
|
|
|
18
19
|
{
|
|
19
20
|
this.regexes = new string[] { regex };
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
public RegexPatternAttribute(string[] regexes)
|
|
24
24
|
{
|
|
25
25
|
this.regexes = regexes;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
|
|
29
28
|
public override void Validate(object parent, FieldInfo fieldInfo, object param)
|
|
30
29
|
{
|
|
31
|
-
if (param is null)
|
|
32
|
-
|
|
30
|
+
if (param is null)
|
|
31
|
+
{
|
|
32
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' must not be null");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
foreach (string regex in regexes)
|
|
33
36
|
{
|
|
34
37
|
var match = Regex.Match(param.ToString(), regex);
|
|
35
|
-
if (match
|
|
38
|
+
if (match.Success) return;
|
|
36
39
|
}
|
|
37
|
-
|
|
40
|
+
KlavarException.ThrowErrorOnField(parent, fieldInfo, $"Field '{fieldInfo.Name}' is not match as {this.GetType().Name.Replace("Attribute", "")}");
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
using System;
|
|
2
|
+
using System.Reflection;
|
|
2
3
|
using Amanotes.Core.Internal;
|
|
3
4
|
using UnityEngine;
|
|
4
5
|
using GUID = System.Guid;
|
|
@@ -13,11 +14,7 @@ namespace Amanotes.Core
|
|
|
13
14
|
|
|
14
15
|
public static void LogEventError(string message)
|
|
15
16
|
{
|
|
16
|
-
|
|
17
|
-
throw new KlavarException(message);
|
|
18
|
-
#else
|
|
19
|
-
Logging.LogError(message);
|
|
20
|
-
#endif
|
|
17
|
+
KlavarException.ThrowIfEditor(message);
|
|
21
18
|
}
|
|
22
19
|
}
|
|
23
20
|
|
|
@@ -25,6 +22,25 @@ namespace Amanotes.Core
|
|
|
25
22
|
{
|
|
26
23
|
public KlavarException() { }
|
|
27
24
|
public KlavarException(string message) : base(message) { }
|
|
25
|
+
|
|
26
|
+
public static void ThrowIfEditor(string message)
|
|
27
|
+
{
|
|
28
|
+
#if UNITY_EDITOR
|
|
29
|
+
throw new KlavarException(message);
|
|
30
|
+
#else
|
|
31
|
+
Logging.LogError(message);
|
|
32
|
+
#endif
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public static void ThrowErrorOnField(object parent, FieldInfo fieldInfo, string message)
|
|
36
|
+
{
|
|
37
|
+
var classType = parent.GetType();
|
|
38
|
+
var eventNameAttr = (EventNameAttribute) Attribute.GetCustomAttribute(classType, typeof(EventNameAttribute), true);
|
|
39
|
+
string eventName = eventNameAttr?.name ?? classType.Name;
|
|
40
|
+
var paramNameAttr = fieldInfo.GetCustomAttribute<NameAttribute>(true);
|
|
41
|
+
string paramName = paramNameAttr?.name ?? fieldInfo.Name;
|
|
42
|
+
ThrowIfEditor($"Error at event '{eventName}' parameter '{paramName}': {message}");
|
|
43
|
+
}
|
|
28
44
|
}
|
|
29
45
|
}
|
|
30
46
|
|
|
@@ -23,7 +23,10 @@ namespace Amanotes.Core
|
|
|
23
23
|
var eventNameAttr = (EventNameAttribute)Attribute.GetCustomAttribute(type, typeof(EventNameAttribute));
|
|
24
24
|
|
|
25
25
|
if (eventNameAttr == null)
|
|
26
|
-
|
|
26
|
+
{
|
|
27
|
+
KlavarException.ThrowIfEditor($"Add `EventName` attribute to class {type.FullName}");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
27
30
|
|
|
28
31
|
var @params = this.ToDict();
|
|
29
32
|
var eventName = eventNameAttr.name;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections;
|
|
3
|
+
using System.Threading;
|
|
4
|
+
using UnityEngine;
|
|
5
|
+
using static Amanotes.Core.Internal.Logging;
|
|
6
|
+
|
|
7
|
+
namespace Amanotes.Core.Internal
|
|
8
|
+
{
|
|
9
|
+
public static partial class GDKUtils
|
|
10
|
+
{
|
|
11
|
+
public static void SafeInvoke(Action action)
|
|
12
|
+
{
|
|
13
|
+
if (action == null) return;
|
|
14
|
+
|
|
15
|
+
if (Application.isEditor)
|
|
16
|
+
{
|
|
17
|
+
action.Invoke();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try
|
|
22
|
+
{
|
|
23
|
+
action.Invoke();
|
|
24
|
+
} catch (Exception e)
|
|
25
|
+
{
|
|
26
|
+
LogError(e.ToString());
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static void SafeInvoke<T>(Action<T> action, T eventObject)
|
|
31
|
+
{
|
|
32
|
+
SafeInvoke(() => action?.Invoke(eventObject));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|