com.amanotes.gdk 0.2.85 → 0.2.87
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 +30 -0
- package/Editor/Extra/GDKCIBuildCommand.cs +19 -2
- package/Editor/Extra/GDKLocalBuild.cs +25 -1
- package/Editor/Extra/SDKVersionTracking.cs +9 -1
- package/Editor/Utils/AmaGDKEditor.ExtractVersion.Max.cs +120 -0
- package/Editor/Utils/AmaGDKEditor.ExtractVersion.Max.cs.meta +3 -0
- package/Editor/Utils/AmaGDKEditor.ExtractVersion.cs +8 -10
- package/Extra/AmaGDKInstaller.unitypackage +0 -0
- package/Extra/AutoEventQC.unitypackage +0 -0
- package/Extra/CheckDiskSpace.unitypackage +0 -0
- package/Extra/Consent.unitypackage +0 -0
- package/Extra/CrashlyticHook.unitypackage +0 -0
- package/Extra/ForceUpdate.unitypackage +0 -0
- package/Extra/LegacyGDKUpdateHelper.unitypackage +0 -0
- package/Extra/PostProcessor.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.AdQuality.unitypackage +0 -0
- package/Packages/IronSourceAdapter.unitypackage +0 -0
- package/Packages/MaxAdNetworkAdapter.unitypackage +0 -0
- package/Packages/RevenueCatAdapter.unitypackage +0 -0
- package/Packages/SqliteAnalyticsAdapter.unitypackage +0 -0
- package/Runtime/Ad/AdLogic.cs +230 -148
- package/Runtime/AmaGDK.Adapters.cs +2 -0
- package/Runtime/AmaGDK.Analytics.cs +140 -78
- package/Runtime/AmaGDK.RemoteConfig.cs +50 -40
- package/Runtime/AmaGDK.Singleton.cs +2 -0
- package/Runtime/AmaGDK.cs +3 -1
- package/Runtime/AnalyticQualityAsset.cs +69 -38
- package/Runtime/AudioToolkit/Plugins/AudioDeviceDetector.cs +31 -17
- package/Runtime/Core/GDKDispatcher.cs +4 -2
- package/Runtime/Core/GDKSemVer.cs +23 -26
- package/Runtime/Fps/AmaFPSVisualizer.cs +48 -26
- package/Runtime/Internal/AmaGDK.Utils.cs +90 -46
- package/Runtime/Internal/ForceQuitMonitor.cs +43 -31
- package/Runtime/Klavar/Attributes/MinMaxAttribute.cs +12 -3
- package/Runtime/UI/ScrollView/GDKScrollView.cs +83 -48
- package/Runtime/Utils/GDKFileUtils.cs +3 -8
- package/Runtime/Utils/GDKUtils.cs +20 -8
- package/package.json +1 -1
|
@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
|
|
|
3
3
|
using System.Collections.Generic;
|
|
4
4
|
using System.Text;
|
|
5
5
|
using Amanotes.Core.Internal;
|
|
6
|
+
using System.Linq;
|
|
6
7
|
using UnityEngine;
|
|
7
8
|
using UnityEngine.Profiling;
|
|
8
9
|
using static Amanotes.Core.AmaGDK.Analytics;
|
|
@@ -90,7 +91,7 @@ namespace Amanotes.Core
|
|
|
90
91
|
return !allowAdapterIds.Contains(adapterId);
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
LogWarning("[AmaGDK] Should never be here: overrideConfig == true but no id in listAdapterIds!");
|
|
94
95
|
return false;
|
|
95
96
|
}
|
|
96
97
|
|
|
@@ -106,8 +107,14 @@ namespace Amanotes.Core
|
|
|
106
107
|
|
|
107
108
|
public static IEventParamsBuilder LogEvent(string eventName)
|
|
108
109
|
{
|
|
110
|
+
if (listAdapters.Count == 0)
|
|
111
|
+
{
|
|
112
|
+
InitModule();
|
|
113
|
+
}
|
|
114
|
+
|
|
109
115
|
var result = PrepareEvent(eventName);
|
|
110
116
|
eventQueue.Enqueue(result);
|
|
117
|
+
Log($"Queued Event <{result.eventName}>");
|
|
111
118
|
return result;
|
|
112
119
|
}
|
|
113
120
|
|
|
@@ -364,6 +371,7 @@ namespace Amanotes.Core
|
|
|
364
371
|
{
|
|
365
372
|
sessionStat = new SessionStat();
|
|
366
373
|
}
|
|
374
|
+
|
|
367
375
|
listAdapters.Clear();
|
|
368
376
|
listAdapters.AddRange(Adapter2.GetAllAdapter<AnalyticsAdapter>());
|
|
369
377
|
}
|
|
@@ -448,35 +456,53 @@ namespace Amanotes.Core
|
|
|
448
456
|
string eventNameToSend = GetEventNameToSend(eventParams.eventName, countInSession, totalCount);
|
|
449
457
|
AnalyticsConfig config = Config.analytics;
|
|
450
458
|
if (config.normalizeEventName) NormalizeEventName(ref eventNameToSend);
|
|
451
|
-
|
|
452
|
-
if (config.showAnalyticsLog)
|
|
453
|
-
{
|
|
454
|
-
ForceLog($"[Analytics] Event <{eventNameToSend}> (in session: {countInSession}, total: {totalCount})\n{JsonUtils.DictionaryToJson(eventParams.parameters, true)}");
|
|
455
|
-
}
|
|
456
|
-
|
|
457
459
|
config.quality.CheckEventQuality(eventParams.eventName, eventParams.parameters);
|
|
458
460
|
|
|
459
|
-
|
|
461
|
+
List<string> inUseAdapterIDs = config.enableEventStat ? new List<string>(listAdapters.Count) : null;
|
|
462
|
+
bool effective = ProcessAdapters(eventParams, eventNameToSend, inUseAdapterIDs);
|
|
463
|
+
HandleEventResult(effective, config, eventNameToSend, countInSession, totalCount, eventParams, inUseAdapterIDs);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
private static bool ProcessAdapters(EventParams eventParams, string eventNameToSend, List<string> inUseAdapterIDs)
|
|
467
|
+
{
|
|
468
|
+
var effective = false;
|
|
460
469
|
foreach (AnalyticsAdapter m in listAdapters)
|
|
461
470
|
{
|
|
462
|
-
if (eventParams
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
//
|
|
466
|
-
// Once set overrideConfig, we should skip the adapter config completely!!!
|
|
467
|
-
//
|
|
468
|
-
if (eventParams.IsAdapterForbidden(m.adapterId)) continue;
|
|
469
|
-
}
|
|
470
|
-
else // Do not remove else
|
|
471
|
-
{
|
|
472
|
-
if (m.IsForbidden(eventParams.eventName)) continue;
|
|
473
|
-
}
|
|
471
|
+
if (ShouldSkipAdapter(eventParams, m)) continue;
|
|
472
|
+
|
|
473
|
+
effective = true;
|
|
474
474
|
m.LogEvent(eventNameToSend, eventParams.parameters);
|
|
475
475
|
inUseAdapterIDs?.Add(m.adapterId);
|
|
476
476
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
477
|
+
return effective;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
private static bool ShouldSkipAdapter(EventParams eventParams, AnalyticsAdapter adapter)
|
|
481
|
+
{
|
|
482
|
+
// IMPORTANT NOTE:
|
|
483
|
+
//
|
|
484
|
+
// Once set overrideConfig, we should skip the adapter config completely!!!
|
|
485
|
+
//
|
|
486
|
+
return eventParams.overrideConfig
|
|
487
|
+
? eventParams.IsAdapterForbidden(adapter.adapterId)
|
|
488
|
+
: adapter.IsForbidden(eventParams.eventName);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
private static void HandleEventResult(bool effective, AnalyticsConfig config, string eventNameToSend, int countInSession, int totalCount, EventParams eventParams, List<string> inUseAdapterIDs)
|
|
492
|
+
{
|
|
493
|
+
if (effective)
|
|
494
|
+
{
|
|
495
|
+
if (config.showAnalyticsLog)
|
|
496
|
+
{
|
|
497
|
+
ForceLog($"[Analytics] Event <{eventNameToSend}> (in session: {countInSession}, total: {totalCount})\n{JsonUtils.DictionaryToJson(eventParams.parameters, true)}");
|
|
498
|
+
}
|
|
499
|
+
GDKUtils.SafeInvoke(OnEventSent, eventNameToSend, eventParams.parameters);
|
|
500
|
+
sessionStat?.OnEventSent(eventNameToSend, eventParams.parameters, inUseAdapterIDs);
|
|
501
|
+
}
|
|
502
|
+
else
|
|
503
|
+
{
|
|
504
|
+
LogError($"Event <{eventParams}> has been skipped (no matching Adapter)\n{JsonUtility.ToJson(eventParams)}");
|
|
505
|
+
}
|
|
480
506
|
}
|
|
481
507
|
|
|
482
508
|
internal static void LogEventImmediately(EventParams eventParams)
|
|
@@ -551,63 +577,89 @@ namespace Amanotes.Core
|
|
|
551
577
|
var hasChanged = false;
|
|
552
578
|
var trimKey = key.Trim();
|
|
553
579
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
if (c == '_' || isLetter || isNumber)
|
|
560
|
-
{
|
|
561
|
-
tempKey.Append(c);
|
|
562
|
-
continue;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
hasChanged = true;
|
|
566
|
-
if (c == ' ' || c == '-')
|
|
567
|
-
{
|
|
568
|
-
tempKey.Append('_');
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
if (hasChanged && willLog)
|
|
573
|
-
{
|
|
574
|
-
tempLog.Append(" - Name may only contain alphanumeric characters and underscores");
|
|
575
|
-
}
|
|
580
|
+
hasChanged = ProcessCharacters(trimKey, tempKey, tempLog, willLog, hasChanged);
|
|
581
|
+
hasChanged = EnsureValidStart(tempKey, tempLog, willLog, hasChanged, key);
|
|
582
|
+
hasChanged = HandleReservedPrefixes(tempKey, tempLog, willLog, hasChanged, key);
|
|
583
|
+
hasChanged = ValidateLength(trimKey, tempKey, tempLog, willLog, hasChanged, key);
|
|
576
584
|
|
|
577
|
-
|
|
578
|
-
{
|
|
579
|
-
hasChanged = true;
|
|
580
|
-
tempKey.Insert(0, 'E');
|
|
581
|
-
if (willLog) tempLog.Append($" - Name must start with a letter: <{key}>");
|
|
582
|
-
}
|
|
585
|
+
ApplyChanges(dryRun, warningLog, tempLog, hasChanged, ref key, tempKey);
|
|
583
586
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
tempKey.Insert(0, prefix.Value);
|
|
590
|
-
if (willLog) tempLog.AppendLine($" - <{key}> starts with reserved prefix <{prefix}>");
|
|
591
|
-
}
|
|
587
|
+
GDKPool.Return(tempLog);
|
|
588
|
+
GDKPool.Return(tempKey);
|
|
589
|
+
}
|
|
590
|
+
Profiler.EndSample();
|
|
591
|
+
}
|
|
592
592
|
|
|
593
|
-
|
|
593
|
+
private static bool ProcessCharacters(string trimKey, StringBuilder tempKey, StringBuilder tempLog, bool willLog, bool hasChanged)
|
|
594
|
+
{
|
|
595
|
+
foreach (var c in trimKey)
|
|
596
|
+
{
|
|
597
|
+
var isLetter = IsAlphabet(c);
|
|
598
|
+
var isNumber = char.IsDigit(c);
|
|
599
|
+
|
|
600
|
+
if (c == '_' || isLetter || isNumber)
|
|
594
601
|
{
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
tempKey.Length = 40;
|
|
602
|
+
tempKey.Append(c);
|
|
603
|
+
continue;
|
|
598
604
|
}
|
|
599
605
|
|
|
600
|
-
|
|
606
|
+
hasChanged = true;
|
|
607
|
+
if (c == ' ' || c == '-')
|
|
601
608
|
{
|
|
602
|
-
|
|
603
|
-
} else {
|
|
604
|
-
if (hasChanged) key = tempKey.ToString();
|
|
609
|
+
tempKey.Append('_');
|
|
605
610
|
}
|
|
606
|
-
|
|
607
|
-
GDKPool.Return(tempLog);
|
|
608
|
-
GDKPool.Return(tempKey);
|
|
609
611
|
}
|
|
610
|
-
|
|
612
|
+
|
|
613
|
+
if (hasChanged && willLog)
|
|
614
|
+
{
|
|
615
|
+
tempLog.Append(" - Name may only contain alphanumeric characters and underscores");
|
|
616
|
+
}
|
|
617
|
+
return hasChanged;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
private static bool EnsureValidStart(StringBuilder tempKey, StringBuilder tempLog, bool willLog, bool hasChanged, string key)
|
|
621
|
+
{
|
|
622
|
+
if (tempKey.Length > 0 && !IsAlphabet(tempKey[0]))
|
|
623
|
+
{
|
|
624
|
+
hasChanged = true;
|
|
625
|
+
tempKey.Insert(0, 'E');
|
|
626
|
+
if (willLog) tempLog.Append($" - Name must start with a letter: <{key}>");
|
|
627
|
+
}
|
|
628
|
+
return hasChanged;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
private static bool HandleReservedPrefixes(StringBuilder tempKey, StringBuilder tempLog, bool willLog, bool hasChanged, string key)
|
|
632
|
+
{
|
|
633
|
+
foreach (var prefix in reservedPrefixes)
|
|
634
|
+
{
|
|
635
|
+
if (tempKey.Length < prefix.Key.Length || !StringStartsWith(tempKey, prefix.Key)) continue;
|
|
636
|
+
hasChanged = true;
|
|
637
|
+
tempKey.Remove(0, prefix.Key.Length);
|
|
638
|
+
tempKey.Insert(0, prefix.Value);
|
|
639
|
+
if (willLog) tempLog.AppendLine($" - <{key}> starts with reserved prefix <{prefix}>");
|
|
640
|
+
}
|
|
641
|
+
return hasChanged;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
private static bool ValidateLength(string trimKey, StringBuilder tempKey, StringBuilder tempLog, bool willLog, bool hasChanged, string key)
|
|
645
|
+
{
|
|
646
|
+
if (trimKey.Length > 40)
|
|
647
|
+
{
|
|
648
|
+
hasChanged = true;
|
|
649
|
+
if (willLog) tempLog.AppendLine($" - Name is too long ({key.Length} > 40): <{key}> ");
|
|
650
|
+
tempKey.Length = 40;
|
|
651
|
+
}
|
|
652
|
+
return hasChanged;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
private static void ApplyChanges(bool dryRun, StringBuilder warningLog, StringBuilder tempLog, bool hasChanged, ref string key, StringBuilder tempKey)
|
|
656
|
+
{
|
|
657
|
+
if (dryRun)
|
|
658
|
+
{
|
|
659
|
+
warningLog.Append(tempLog);
|
|
660
|
+
} else {
|
|
661
|
+
if (hasChanged) key = tempKey.ToString();
|
|
662
|
+
}
|
|
611
663
|
}
|
|
612
664
|
|
|
613
665
|
private static bool StringStartsWith(StringBuilder stringBuilder, string prefix)
|
|
@@ -777,7 +829,7 @@ namespace Amanotes.Core
|
|
|
777
829
|
{
|
|
778
830
|
if (cachedEventDetails.ContainsKey(ed.eventName))
|
|
779
831
|
{
|
|
780
|
-
|
|
832
|
+
LogWarning($"EventName <{ed.eventName}> existed!");
|
|
781
833
|
return false;
|
|
782
834
|
}
|
|
783
835
|
|
|
@@ -1039,18 +1091,28 @@ namespace Amanotes.Core
|
|
|
1039
1091
|
LogWarning("OnlyTo() can only be set once!");
|
|
1040
1092
|
return ap;
|
|
1041
1093
|
}
|
|
1042
|
-
|
|
1043
|
-
eventData.overrideConfig = true;
|
|
1044
|
-
eventData.allowAdapterIds ??= GDKPool.GetHashSet();
|
|
1045
1094
|
|
|
1095
|
+
var h = GDKPool.GetHashSet();
|
|
1046
1096
|
foreach (string mId in analyticIds)
|
|
1047
1097
|
{
|
|
1048
|
-
if (!listAdapters.Exists(a => a.adapterId == mId))
|
|
1098
|
+
if (listAdapters.Count > 0 && !listAdapters.Exists(a => a.adapterId == mId))
|
|
1049
1099
|
{
|
|
1050
|
-
LogError($"Cannot send event <{eventData.eventName}> to <{mId}>. Analytics adapter for <{mId}> is not available
|
|
1100
|
+
LogError($"Cannot send event <{eventData.eventName}> to <{mId}>. Analytics adapter for <{mId}> is not available.\n" +
|
|
1101
|
+
$"listAdapters ({listAdapters.Count}): [{string.Join(",", listAdapters.Select(item=>item.adapterId).ToArray())}]");
|
|
1051
1102
|
continue;
|
|
1052
1103
|
}
|
|
1053
|
-
|
|
1104
|
+
h.Add(mId);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
eventData.overrideConfig = true;
|
|
1108
|
+
if (h.Count > 0)
|
|
1109
|
+
{
|
|
1110
|
+
eventData.allowAdapterIds ??= h;
|
|
1111
|
+
}
|
|
1112
|
+
else
|
|
1113
|
+
{
|
|
1114
|
+
// No valid adapters found, create empty set to ensure event is skipped
|
|
1115
|
+
eventData.allowAdapterIds ??= GDKPool.GetHashSet();
|
|
1054
1116
|
}
|
|
1055
1117
|
|
|
1056
1118
|
return ap;
|
|
@@ -259,43 +259,9 @@ namespace Amanotes.Core
|
|
|
259
259
|
try
|
|
260
260
|
{
|
|
261
261
|
DictConfig.Clear();
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
string firstLine = sr.ReadLine();
|
|
266
|
-
if (firstLine == null)
|
|
267
|
-
{
|
|
268
|
-
NextState(false);
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
if (ShouldClearCache(firstLine))
|
|
272
|
-
{
|
|
273
|
-
GDKFileUtils.Delete(fileName);
|
|
274
|
-
string oldVersion = firstLine.StartsWith(VERSION_PREFIX) ? firstLine : "<none>";
|
|
275
|
-
Log($"[RemoteConfig] Cached remote config cleared due to embed version changed:\n{oldVersion} -> {EmbedVersion}");
|
|
276
|
-
NextState(false);
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
//Read key-value
|
|
281
|
-
string line;
|
|
282
|
-
int lineNo = 1;
|
|
283
|
-
while ((line = sr.ReadLine()) != null)
|
|
284
|
-
{
|
|
285
|
-
lineNo++;
|
|
286
|
-
var idx = line.IndexOf('\t');
|
|
287
|
-
if (idx == -1)
|
|
288
|
-
{
|
|
289
|
-
LogWarning($"[RemoteConfig] Cannot get (key, value) at line {lineNo} of cache. Content:\n<{line}>");
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
string key = line.Substring(0, idx);
|
|
293
|
-
string value = line.Substring(idx + 1);
|
|
294
|
-
DictConfig.Add(key, Decode(value));
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
Source = RemoteConfigSource.LocalCache;
|
|
298
|
-
Log("[RemoteConfig] Load from cache");
|
|
262
|
+
bool success = ReadCacheFile();
|
|
263
|
+
Profiler.EndSample();
|
|
264
|
+
NextState(success);
|
|
299
265
|
}
|
|
300
266
|
catch (Exception ex)
|
|
301
267
|
{
|
|
@@ -303,11 +269,55 @@ namespace Amanotes.Core
|
|
|
303
269
|
_cacheExisted = false;
|
|
304
270
|
Profiler.EndSample();
|
|
305
271
|
NextState(false);
|
|
306
|
-
return;
|
|
307
272
|
}
|
|
273
|
+
}
|
|
308
274
|
|
|
309
|
-
|
|
310
|
-
|
|
275
|
+
static bool ReadCacheFile()
|
|
276
|
+
{
|
|
277
|
+
using (StreamReader sr = new StreamReader(GDKFileUtils.GetPath(fileName)))
|
|
278
|
+
{
|
|
279
|
+
string firstLine = sr.ReadLine();
|
|
280
|
+
if (firstLine == null) return false;
|
|
281
|
+
|
|
282
|
+
if (!ValidateCacheVersion(firstLine)) return false;
|
|
283
|
+
|
|
284
|
+
ReadConfigKeyValues(sr);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
Source = RemoteConfigSource.LocalCache;
|
|
288
|
+
Log("[RemoteConfig] Load from cache");
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
static bool ValidateCacheVersion(string firstLine)
|
|
293
|
+
{
|
|
294
|
+
if (ShouldClearCache(firstLine))
|
|
295
|
+
{
|
|
296
|
+
GDKFileUtils.Delete(fileName);
|
|
297
|
+
string oldVersion = firstLine.StartsWith(VERSION_PREFIX) ? firstLine : "<none>";
|
|
298
|
+
Log($"[RemoteConfig] Cached remote config cleared due to embed version changed:\n{oldVersion} -> {EmbedVersion}");
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
static void ReadConfigKeyValues(StreamReader sr)
|
|
305
|
+
{
|
|
306
|
+
string line;
|
|
307
|
+
int lineNo = 1;
|
|
308
|
+
while ((line = sr.ReadLine()) != null)
|
|
309
|
+
{
|
|
310
|
+
lineNo++;
|
|
311
|
+
var idx = line.IndexOf('\t');
|
|
312
|
+
if (idx == -1)
|
|
313
|
+
{
|
|
314
|
+
LogWarning($"[RemoteConfig] Cannot get (key, value) at line {lineNo} of cache. Content:\n<{line}>");
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
string key = line.Substring(0, idx);
|
|
318
|
+
string value = line.Substring(idx + 1);
|
|
319
|
+
DictConfig.Add(key, Decode(value));
|
|
320
|
+
}
|
|
311
321
|
}
|
|
312
322
|
|
|
313
323
|
static void LoadEmbedConfig()
|
package/Runtime/AmaGDK.cs
CHANGED
|
@@ -27,7 +27,7 @@ namespace Amanotes.Core
|
|
|
27
27
|
{
|
|
28
28
|
public partial class AmaGDK : MonoBehaviour
|
|
29
29
|
{
|
|
30
|
-
public const string VERSION = "0.2.
|
|
30
|
+
public const string VERSION = "0.2.87";
|
|
31
31
|
|
|
32
32
|
internal static Status _status = Status.None;
|
|
33
33
|
internal static ConfigAsset _config = null;
|
|
@@ -200,6 +200,8 @@ namespace Amanotes.Core
|
|
|
200
200
|
|
|
201
201
|
IEnumerator InitRoutine()
|
|
202
202
|
{
|
|
203
|
+
Log("InitRoutine!");
|
|
204
|
+
|
|
203
205
|
_allowInit = _allowInit || autoInit;
|
|
204
206
|
|
|
205
207
|
if (Config == null)
|
|
@@ -54,31 +54,27 @@ namespace Amanotes.Core
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
|
|
58
|
+
{
|
|
59
|
+
typeof(int), typeof(long), typeof(short), typeof(byte),
|
|
60
|
+
typeof(double), typeof(float), typeof(decimal),
|
|
61
|
+
typeof(uint), typeof(ulong), typeof(ushort), typeof(sbyte)
|
|
62
|
+
};
|
|
63
|
+
|
|
57
64
|
private bool IsNumericType(Type type)
|
|
58
65
|
{
|
|
59
|
-
return type
|
|
60
|
-
type == typeof(long) ||
|
|
61
|
-
type == typeof(short) ||
|
|
62
|
-
type == typeof(byte) ||
|
|
63
|
-
type == typeof(double) ||
|
|
64
|
-
type == typeof(float) ||
|
|
65
|
-
type == typeof(decimal) ||
|
|
66
|
-
type == typeof(uint) ||
|
|
67
|
-
type == typeof(ulong) ||
|
|
68
|
-
type == typeof(ushort) ||
|
|
69
|
-
type == typeof(sbyte);
|
|
66
|
+
return NumericTypes.Contains(type);
|
|
70
67
|
}
|
|
71
68
|
|
|
69
|
+
private static readonly HashSet<Type> IntegerTypes = new HashSet<Type>
|
|
70
|
+
{
|
|
71
|
+
typeof(sbyte), typeof(byte), typeof(short), typeof(ushort),
|
|
72
|
+
typeof(int), typeof(uint), typeof(long), typeof(ulong)
|
|
73
|
+
};
|
|
74
|
+
|
|
72
75
|
private bool IsIntegerType(Type type)
|
|
73
76
|
{
|
|
74
|
-
return type
|
|
75
|
-
type == typeof(byte) ||
|
|
76
|
-
type == typeof(short) ||
|
|
77
|
-
type == typeof(ushort) ||
|
|
78
|
-
type == typeof(int) ||
|
|
79
|
-
type == typeof(uint) ||
|
|
80
|
-
type == typeof(long) ||
|
|
81
|
-
type == typeof(ulong);
|
|
77
|
+
return IntegerTypes.Contains(type);
|
|
82
78
|
}
|
|
83
79
|
|
|
84
80
|
internal void ValidateParams(string eventName, Dictionary<string, object> eventParams)
|
|
@@ -89,6 +85,19 @@ namespace Amanotes.Core
|
|
|
89
85
|
var isValid = true;
|
|
90
86
|
HashSet<string> checkedParameters = GDKPool.GetHashSet();
|
|
91
87
|
|
|
88
|
+
isValid &= ValidateRequiredParams(eventParams, logBuilder, checkedParameters);
|
|
89
|
+
isValid &= ValidateExtraParams(eventParams, logBuilder, checkedParameters);
|
|
90
|
+
|
|
91
|
+
if (!isValid) LogWarningOnce(logBuilder.ToString());
|
|
92
|
+
|
|
93
|
+
GDKPool.Return(logBuilder);
|
|
94
|
+
GDKPool.Return(checkedParameters);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private bool ValidateRequiredParams(Dictionary<string, object> eventParams, StringBuilder logBuilder, HashSet<string> checkedParameters)
|
|
98
|
+
{
|
|
99
|
+
bool isValid = true;
|
|
100
|
+
|
|
92
101
|
foreach (var kvp in DicParam)
|
|
93
102
|
{
|
|
94
103
|
if (!eventParams.TryGetValue(kvp.Key, out object paramValue))
|
|
@@ -109,7 +118,14 @@ namespace Amanotes.Core
|
|
|
109
118
|
|
|
110
119
|
checkedParameters.Add(kvp.Key);
|
|
111
120
|
}
|
|
121
|
+
|
|
122
|
+
return isValid;
|
|
123
|
+
}
|
|
112
124
|
|
|
125
|
+
private bool ValidateExtraParams(Dictionary<string, object> eventParams, StringBuilder logBuilder, HashSet<string> checkedParameters)
|
|
126
|
+
{
|
|
127
|
+
bool isValid = true;
|
|
128
|
+
|
|
113
129
|
foreach (var parameter in eventParams)
|
|
114
130
|
{
|
|
115
131
|
if (checkedParameters.Contains(parameter.Key)) continue;
|
|
@@ -118,10 +134,7 @@ namespace Amanotes.Core
|
|
|
118
134
|
logBuilder.AppendLine($"[+] {parameter.Key}");
|
|
119
135
|
}
|
|
120
136
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
GDKPool.Return(logBuilder);
|
|
124
|
-
GDKPool.Return(checkedParameters);
|
|
137
|
+
return isValid;
|
|
125
138
|
}
|
|
126
139
|
|
|
127
140
|
private bool ValidateParamType(object paramValue, ParamType paramType)
|
|
@@ -188,26 +201,44 @@ namespace Amanotes.Core
|
|
|
188
201
|
|
|
189
202
|
foreach (EventQuality eventQuality in lstEvent)
|
|
190
203
|
{
|
|
191
|
-
|
|
204
|
+
ValidateEventName(eventQuality.eventName, eventNames);
|
|
205
|
+
ValidateEventParameters(eventQuality);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
GDKPool.Return(eventNames);
|
|
209
|
+
EditorUtility.SetDirty(this);
|
|
210
|
+
}
|
|
192
211
|
|
|
193
|
-
|
|
212
|
+
private void ValidateEventName(string eventName, HashSet<string> eventNames)
|
|
213
|
+
{
|
|
214
|
+
if (string.IsNullOrWhiteSpace(eventName))
|
|
215
|
+
Debug.LogWarning("Event name cannot be empty or whitespace.");
|
|
194
216
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
foreach (var param in eventQuality.lstParam)
|
|
200
|
-
{
|
|
201
|
-
if (string.IsNullOrWhiteSpace(param.paramName)) Debug.LogWarning("Event parameter name cannot be empty or whitespace.");
|
|
217
|
+
if (!eventNames.Add(eventName))
|
|
218
|
+
Debug.LogWarning($"Duplicate event name found: {eventName}. Event names must be unique.");
|
|
219
|
+
}
|
|
202
220
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
221
|
+
private void ValidateEventParameters(EventQuality eventQuality)
|
|
222
|
+
{
|
|
223
|
+
HashSet<string> paramNames = GDKPool.GetHashSet();
|
|
224
|
+
|
|
225
|
+
eventQuality.lstParam = eventQuality.lstParam.OrderBy(param => param.paramName).ToList();
|
|
226
|
+
|
|
227
|
+
foreach (var param in eventQuality.lstParam)
|
|
228
|
+
{
|
|
229
|
+
ValidateParameterName(param.paramName, eventQuality.eventName, paramNames);
|
|
207
230
|
}
|
|
208
231
|
|
|
209
|
-
GDKPool.Return(
|
|
210
|
-
|
|
232
|
+
GDKPool.Return(paramNames);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private void ValidateParameterName(string paramName, string eventName, HashSet<string> paramNames)
|
|
236
|
+
{
|
|
237
|
+
if (string.IsNullOrWhiteSpace(paramName))
|
|
238
|
+
Debug.LogWarning("Event parameter name cannot be empty or whitespace.");
|
|
239
|
+
|
|
240
|
+
if (!paramNames.Add(paramName))
|
|
241
|
+
Debug.LogWarning($"Duplicate parameter name found in event {eventName}: {paramName}. Parameter names must be unique within an event.");
|
|
211
242
|
}
|
|
212
243
|
#endif
|
|
213
244
|
|
|
@@ -162,10 +162,7 @@ namespace Amanotes.Core
|
|
|
162
162
|
|
|
163
163
|
private static string RemoveSurrogatePairs(string str, string replacementCharacter = "?")
|
|
164
164
|
{
|
|
165
|
-
if (str == null)
|
|
166
|
-
{
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
165
|
+
if (str == null) return null;
|
|
169
166
|
|
|
170
167
|
StringBuilder sb = null;
|
|
171
168
|
for (var i = 0; i < str.Length; i++)
|
|
@@ -174,19 +171,8 @@ namespace Amanotes.Core
|
|
|
174
171
|
|
|
175
172
|
if (char.IsSurrogate(ch))
|
|
176
173
|
{
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
sb = GDKPool.GetStringBuilder();
|
|
180
|
-
sb.Append(str, 0, i);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
sb.Append(replacementCharacter);
|
|
184
|
-
|
|
185
|
-
// If there is a high+low surrogate, skip the low surrogate
|
|
186
|
-
if (i + 1 < str.Length && char.IsHighSurrogate(ch) && char.IsLowSurrogate(str[i + 1]))
|
|
187
|
-
{
|
|
188
|
-
i++;
|
|
189
|
-
}
|
|
174
|
+
sb = HandleSurrogateCharacter(str, i, sb, replacementCharacter, out int skipCount);
|
|
175
|
+
i += skipCount;
|
|
190
176
|
}
|
|
191
177
|
else
|
|
192
178
|
{
|
|
@@ -196,6 +182,34 @@ namespace Amanotes.Core
|
|
|
196
182
|
|
|
197
183
|
return sb == null ? str : GDKPool.ReturnString(sb);
|
|
198
184
|
}
|
|
185
|
+
|
|
186
|
+
private static StringBuilder HandleSurrogateCharacter(string str, int index, StringBuilder sb, string replacementCharacter, out int skipCount)
|
|
187
|
+
{
|
|
188
|
+
skipCount = 0;
|
|
189
|
+
|
|
190
|
+
if (sb == null)
|
|
191
|
+
{
|
|
192
|
+
sb = GDKPool.GetStringBuilder();
|
|
193
|
+
sb.Append(str, 0, index);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
sb.Append(replacementCharacter);
|
|
197
|
+
|
|
198
|
+
// If there is a high+low surrogate, skip the low surrogate
|
|
199
|
+
if (ShouldSkipLowSurrogate(str, index))
|
|
200
|
+
{
|
|
201
|
+
skipCount = 1;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return sb;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
private static bool ShouldSkipLowSurrogate(string str, int index)
|
|
208
|
+
{
|
|
209
|
+
return index + 1 < str.Length &&
|
|
210
|
+
char.IsHighSurrogate(str[index]) &&
|
|
211
|
+
char.IsLowSurrogate(str[index + 1]);
|
|
212
|
+
}
|
|
199
213
|
}
|
|
200
214
|
|
|
201
215
|
internal enum AudioDeviceType
|
|
@@ -44,9 +44,11 @@ namespace Amanotes.Core.Internal
|
|
|
44
44
|
return false;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
// Fix: https://amanotes.sentry.io/issues/6366288384/events/d45dd8fb736f43d0a8e2aec0df0f173d/
|
|
48
|
+
int argsLength = args != null ? args.Length : 0;
|
|
49
|
+
if (argsLength != nParams)
|
|
48
50
|
{
|
|
49
|
-
GDKUtils.ThrowExceptionInEditor($"Dispatch <{eventName}> with incorrect number of params, expecting {nParams}, got {
|
|
51
|
+
GDKUtils.ThrowExceptionInEditor($"Dispatch <{eventName}> with incorrect number of params, expecting {nParams}, got {argsLength}!",
|
|
50
52
|
(m) => new TargetParameterCountException(m));
|
|
51
53
|
return false;
|
|
52
54
|
}
|