com.amanotes.gdk 0.2.69 → 0.2.70
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 +5 -0
- package/Editor/AmaGDKEditor.cs +2 -1
- package/Editor/Utils/AmaGDKEditor.ExtractVersion.cs +6 -0
- package/Extra/AmaGDKInstaller.unitypackage +0 -0
- package/Extra/CheckDiskSpace.unitypackage +0 -0
- package/Extra/Consent.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.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 +6 -3
- package/Runtime/AmaGDK.Analytics.cs +45 -38
- package/Runtime/AmaGDK.Device.cs +4 -4
- package/Runtime/AmaGDK.RemoteConfig.cs +3 -1
- package/Runtime/AmaGDK.cs +4 -2
- package/Runtime/AnalyticQualityAsset.cs +16 -9
- package/Runtime/AudioToolkit/Plugins/AudioDeviceDetector.cs +13 -12
- package/Runtime/Core/GDKPool.cs +83 -17
- package/Runtime/Internal/AmaGDK.Internal.cs +2 -5
- package/Runtime/Internal/AmaGDK.Utils.cs +32 -81
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.70 - 2024-08-02]
|
|
4
|
+
- [Fix] onAdResult call multiple times
|
|
5
|
+
- [Dev] Show SQLite analytics in GDK Inspector
|
|
6
|
+
- [Dev] Reduce GC by reuse StringBuilders
|
|
7
|
+
|
|
3
8
|
## [0.2.69 - 2024-07-26]
|
|
4
9
|
- [Fix] disable Max adapter
|
|
5
10
|
- [Dev] Update OnAdResult callback
|
package/Editor/AmaGDKEditor.cs
CHANGED
|
@@ -185,6 +185,7 @@ namespace Amanotes.Editor
|
|
|
185
185
|
case IRONSOURCE: return IronSource();
|
|
186
186
|
case MAX: return Max();
|
|
187
187
|
case REVENUECAT: return RevenueCat();
|
|
188
|
+
case SQLITE_ANALYTICS: return SqliteAnalytics();
|
|
188
189
|
default:
|
|
189
190
|
Debug.LogWarning($"Unsupported sdkID <{sdkId}>");
|
|
190
191
|
break;
|
|
@@ -329,6 +330,11 @@ namespace Amanotes.Editor
|
|
|
329
330
|
return version?.Trim();
|
|
330
331
|
}
|
|
331
332
|
|
|
333
|
+
internal static string SqliteAnalytics()
|
|
334
|
+
{
|
|
335
|
+
return "1.0.0";
|
|
336
|
+
}
|
|
337
|
+
|
|
332
338
|
internal static string RevenueCat()
|
|
333
339
|
{
|
|
334
340
|
string[] files = Directory.GetFiles("Assets", "PurchasesWrapper.java", SearchOption.AllDirectories);
|
|
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
|
|
Binary file
|
package/Runtime/Ad/AdLogic.cs
CHANGED
|
@@ -320,9 +320,7 @@ namespace Amanotes.Core.Internal
|
|
|
320
320
|
|
|
321
321
|
_showState = isSuccess ? ShowAdsState.ShowSuccess : ShowAdsState.ShowFail;
|
|
322
322
|
|
|
323
|
-
|
|
324
|
-
context.showFinishAt = Time.realtimeSinceStartup;
|
|
325
|
-
context.onAdResult?.Invoke(isSuccess);
|
|
323
|
+
|
|
326
324
|
|
|
327
325
|
var localData = Ads.localData;
|
|
328
326
|
var stat = _isInterstitial ? localData.interstitial : localData.reward;
|
|
@@ -341,8 +339,13 @@ namespace Amanotes.Core.Internal
|
|
|
341
339
|
TriggerOnAfterAdShow();
|
|
342
340
|
|
|
343
341
|
Log($"[Ad] {adType} ShowAdRoutineCompleted: {isSuccess}\n{JsonUtility.ToJson(Ads.context)}");
|
|
342
|
+
|
|
343
|
+
// Extra callback
|
|
344
|
+
context.showFinishAt = Time.realtimeSinceStartup;
|
|
345
|
+
var resultCallback = context.onAdResult;
|
|
344
346
|
Ads.context = null;
|
|
345
347
|
_showState = ShowAdsState.None;
|
|
348
|
+
resultCallback?.Invoke(isSuccess);
|
|
346
349
|
}
|
|
347
350
|
|
|
348
351
|
private void TriggerBeforeAdShow()
|
|
@@ -68,8 +68,9 @@ namespace Amanotes.Core
|
|
|
68
68
|
doNotIncreaseCounter = false;
|
|
69
69
|
isLoggedImmediately = false;
|
|
70
70
|
overrideConfig = false;
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
|
|
72
|
+
GDKPool.ReturnAndNullize(ref ignoreAdapterIds);
|
|
73
|
+
GDKPool.ReturnAndNullize(ref allowAdapterIds);
|
|
73
74
|
_detail = null;
|
|
74
75
|
}
|
|
75
76
|
|
|
@@ -307,9 +308,8 @@ namespace Amanotes.Core
|
|
|
307
308
|
internal static readonly List<AnalyticsAdapter> listAdapters = new List<AnalyticsAdapter>();
|
|
308
309
|
internal static readonly AnalyticsData localData = new AnalyticsData().LoadJsonFromFile().BuildCache();
|
|
309
310
|
internal static SessionStat sessionStat;
|
|
310
|
-
internal static readonly GDKPool<
|
|
311
|
-
|
|
312
|
-
|
|
311
|
+
internal static readonly GDKPool.Pool<EventParams> epPool = new GDKPool.Pool<EventParams>(1);
|
|
312
|
+
|
|
313
313
|
internal static readonly Dictionary<string, string> reservedPrefixes = new Dictionary<string, string>()
|
|
314
314
|
{
|
|
315
315
|
{ "firebase_", "frb_" },
|
|
@@ -515,32 +515,31 @@ namespace Amanotes.Core
|
|
|
515
515
|
{
|
|
516
516
|
Profiler.BeginSample("AmaGDK.Analytics.NormalizeEventName()");
|
|
517
517
|
{
|
|
518
|
-
var
|
|
519
|
-
|
|
520
|
-
NormalizeKeyString(ref eventName, sb, dryRun);
|
|
518
|
+
var warningLog = GDKPool.GetStringBuilder(8);
|
|
519
|
+
NormalizeKeyString(ref eventName, warningLog, dryRun);
|
|
521
520
|
if (reservedEvents.Contains(eventName))
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
521
|
+
{
|
|
522
|
+
warningLog.AppendLine($" - EventName <{eventName}> is reserved and should not be used");
|
|
523
|
+
}
|
|
524
|
+
if (warningLog.Length > 0 && dryRun) LogWarningOnce($"NormalizeEventName <{eventName}> warnings:\n{warningLog}\n", $"NormalizeEventName<{eventName}>");
|
|
525
|
+
GDKPool.Return(warningLog);
|
|
525
526
|
}
|
|
526
527
|
Profiler.EndSample();
|
|
527
528
|
}
|
|
528
529
|
|
|
529
530
|
internal static void NormalizeKeyString(ref string key, StringBuilder warningLog, bool dryRun)
|
|
530
531
|
{
|
|
532
|
+
if (string.IsNullOrWhiteSpace(key))
|
|
533
|
+
{
|
|
534
|
+
LogWarning($" - Name should not be empty");
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
|
|
531
538
|
Profiler.BeginSample("AmaGDK.Analytics.NormalizeKeyString()");
|
|
532
539
|
{
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
Profiler.EndSample();
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
var tempLog = Config.common.logLevel == LogLevel.None ? null : sbPool.Get();
|
|
541
|
-
tempLog?.Clear();
|
|
542
|
-
var tempKey = sbPool.Get();
|
|
543
|
-
tempKey.Clear();
|
|
540
|
+
var willLog = Config.common.logLevel != LogLevel.None;
|
|
541
|
+
var tempLog = willLog ? GDKPool.GetStringBuilder() : null;
|
|
542
|
+
var tempKey = GDKPool.GetStringBuilder();
|
|
544
543
|
|
|
545
544
|
var hasChanged = false;
|
|
546
545
|
var trimKey = key.Trim();
|
|
@@ -563,16 +562,16 @@ namespace Amanotes.Core
|
|
|
563
562
|
}
|
|
564
563
|
}
|
|
565
564
|
|
|
566
|
-
if (hasChanged)
|
|
565
|
+
if (hasChanged && willLog)
|
|
567
566
|
{
|
|
568
|
-
tempLog
|
|
567
|
+
tempLog.Append(" - Name may only contain alphanumeric characters and underscores");
|
|
569
568
|
}
|
|
570
569
|
|
|
571
570
|
if (tempKey.Length > 0 && !IsAlphabet(tempKey[0]))
|
|
572
571
|
{
|
|
573
572
|
hasChanged = true;
|
|
574
573
|
tempKey.Insert(0, 'E');
|
|
575
|
-
tempLog
|
|
574
|
+
if (willLog) tempLog.Append($" - Name must start with a letter: <{key}>");
|
|
576
575
|
}
|
|
577
576
|
|
|
578
577
|
foreach (var prefix in reservedPrefixes)
|
|
@@ -581,13 +580,13 @@ namespace Amanotes.Core
|
|
|
581
580
|
hasChanged = true;
|
|
582
581
|
tempKey.Remove(0, prefix.Key.Length);
|
|
583
582
|
tempKey.Insert(0, prefix.Value);
|
|
584
|
-
tempLog
|
|
583
|
+
if (willLog) tempLog.AppendLine($" - <{key}> starts with reserved prefix <{prefix}>");
|
|
585
584
|
}
|
|
586
585
|
|
|
587
586
|
if (trimKey.Length > 40)
|
|
588
587
|
{
|
|
589
588
|
hasChanged = true;
|
|
590
|
-
tempLog
|
|
589
|
+
if (willLog) tempLog.AppendLine($" - Name is too long ({key.Length} > 40): <{key}> ");
|
|
591
590
|
tempKey.Length = 40;
|
|
592
591
|
}
|
|
593
592
|
|
|
@@ -598,8 +597,8 @@ namespace Amanotes.Core
|
|
|
598
597
|
if (hasChanged) key = tempKey.ToString();
|
|
599
598
|
}
|
|
600
599
|
|
|
601
|
-
|
|
602
|
-
|
|
600
|
+
GDKPool.Return(tempLog);
|
|
601
|
+
GDKPool.Return(tempKey);
|
|
603
602
|
}
|
|
604
603
|
Profiler.EndSample();
|
|
605
604
|
}
|
|
@@ -702,9 +701,17 @@ namespace Amanotes.Core
|
|
|
702
701
|
adapters = adapterIDs;
|
|
703
702
|
}
|
|
704
703
|
|
|
705
|
-
public
|
|
704
|
+
public void AppendAsTSV(StringBuilder sb)
|
|
706
705
|
{
|
|
707
|
-
|
|
706
|
+
sb.Append(eventNameToSend);
|
|
707
|
+
sb.Append("\t");
|
|
708
|
+
for (var i = 0; i < adapters.Count; i++)
|
|
709
|
+
{
|
|
710
|
+
sb.Append(adapters[i]);
|
|
711
|
+
if (i < adapters.Count - 1) sb.Append(",");
|
|
712
|
+
}
|
|
713
|
+
sb.Append("\t");
|
|
714
|
+
sb.Append(parameters);
|
|
708
715
|
}
|
|
709
716
|
}
|
|
710
717
|
|
|
@@ -856,8 +863,8 @@ namespace Amanotes.Core
|
|
|
856
863
|
{
|
|
857
864
|
private const string TSV_HEADER_ROW = "EventName\tAdapters\tParameters";
|
|
858
865
|
private readonly string fileName = nameof(SessionStat) + DateTime.Now.ToString("_yyMMdd_HHmmss") + ".tsv";
|
|
859
|
-
private StringBuilder contents = new StringBuilder();
|
|
860
866
|
private bool isFirstSave = true;
|
|
867
|
+
private StringBuilder contents = new StringBuilder(8192);
|
|
861
868
|
private readonly ConcurrentQueue<EventStat> lastFrameEventStats = new ConcurrentQueue<EventStat>();
|
|
862
869
|
internal readonly ConcurrentQueue<EventStat> savedEventStatsInLastFrame = new ConcurrentQueue<EventStat>();
|
|
863
870
|
|
|
@@ -878,10 +885,10 @@ namespace Amanotes.Core
|
|
|
878
885
|
}
|
|
879
886
|
while (lastFrameEventStats.TryDequeue(out var stat))
|
|
880
887
|
{
|
|
881
|
-
|
|
888
|
+
stat.AppendAsTSV(contents);
|
|
882
889
|
savedEventStatsInLastFrame.Enqueue(stat);
|
|
883
890
|
}
|
|
884
|
-
|
|
891
|
+
|
|
885
892
|
GDKFileUtils.SaveAppend(fileName, contents.ToString());
|
|
886
893
|
}
|
|
887
894
|
|
|
@@ -972,7 +979,7 @@ namespace Amanotes.Core
|
|
|
972
979
|
}
|
|
973
980
|
|
|
974
981
|
eventData.overrideConfig = true;
|
|
975
|
-
eventData.ignoreAdapterIds ??=
|
|
982
|
+
eventData.ignoreAdapterIds ??= GDKPool.GetHashSet();
|
|
976
983
|
|
|
977
984
|
foreach (string mId in analyticIds)
|
|
978
985
|
{
|
|
@@ -998,7 +1005,7 @@ namespace Amanotes.Core
|
|
|
998
1005
|
}
|
|
999
1006
|
|
|
1000
1007
|
eventData.overrideConfig = true;
|
|
1001
|
-
eventData.allowAdapterIds ??=
|
|
1008
|
+
eventData.allowAdapterIds ??= GDKPool.GetHashSet();
|
|
1002
1009
|
|
|
1003
1010
|
foreach (string mId in analyticIds)
|
|
1004
1011
|
{
|
|
@@ -1080,12 +1087,12 @@ namespace Amanotes.Core
|
|
|
1080
1087
|
{
|
|
1081
1088
|
string eventName = (ap as EventParams)?.eventName;
|
|
1082
1089
|
|
|
1083
|
-
var sb =
|
|
1090
|
+
var sb = GDKPool.GetStringBuilder();
|
|
1084
1091
|
sb.Clear();
|
|
1085
1092
|
NormalizeKeyString(ref key, sb, AmaGDK.Config.analytics.normalizeEventName);
|
|
1086
1093
|
|
|
1087
1094
|
if (sb.Length > 0) LogWarningOnce($"Warning for event <{eventName}>, param <{key}>:\n{sb}", $"NormalizeParamKey <{eventName}>");
|
|
1088
|
-
|
|
1095
|
+
GDKPool.Return(sb);
|
|
1089
1096
|
|
|
1090
1097
|
if (string.IsNullOrWhiteSpace(key))
|
|
1091
1098
|
{
|
package/Runtime/AmaGDK.Device.cs
CHANGED
|
@@ -67,16 +67,16 @@ namespace Amanotes.Core.Internal
|
|
|
67
67
|
|
|
68
68
|
if (AmaGDK.Config.common.logLevel == LogLevel.Verbose)
|
|
69
69
|
{
|
|
70
|
-
var stringBuilder =
|
|
70
|
+
var stringBuilder = GDKPool.GetStringBuilder();
|
|
71
71
|
stringBuilder.Append("Device info:");
|
|
72
72
|
stringBuilder.AppendLine("DeviceSpec: " + result);
|
|
73
73
|
stringBuilder.AppendLine("systemMemorySize: " + SystemInfo.systemMemorySize);
|
|
74
74
|
stringBuilder.AppendLine("processorCount: " + SystemInfo.processorCount);
|
|
75
75
|
stringBuilder.AppendLine("processorFrequency: " + SystemInfo.processorFrequency);
|
|
76
|
-
stringBuilder.AppendLine("graphicsMemorySize: " + SystemInfo.graphicsMemorySize);
|
|
77
|
-
|
|
78
|
-
Logging.Log(stringBuilder.ToString());
|
|
76
|
+
stringBuilder.AppendLine("graphicsMemorySize: " + SystemInfo.graphicsMemorySize);
|
|
77
|
+
Logging.Log(GDKPool.ReturnString(stringBuilder));
|
|
79
78
|
}
|
|
79
|
+
|
|
80
80
|
return result;
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -214,7 +214,7 @@ namespace Amanotes.Core
|
|
|
214
214
|
Profiler.BeginSample("AmaGDK.RemoteConfig.SaveCache()");
|
|
215
215
|
|
|
216
216
|
_fetchState = FetchState.SaveCache;
|
|
217
|
-
StringBuilder sb =
|
|
217
|
+
StringBuilder sb = GDKPool.GetStringBuilder(8);
|
|
218
218
|
|
|
219
219
|
//Add embedded remote config version to force load from embedded config after app update
|
|
220
220
|
sb.AppendLine($"{VERSION_PREFIX}{EmbedVersion}");
|
|
@@ -226,6 +226,8 @@ namespace Amanotes.Core
|
|
|
226
226
|
|
|
227
227
|
string filePath = GDKFileUtils.GetPath(fileName);
|
|
228
228
|
GDKFileUtils.Save(filePath, sb.ToString());
|
|
229
|
+
GDKPool.Return(sb);
|
|
230
|
+
|
|
229
231
|
Log($"[RemoteConfig] Saved remote config to {filePath}");
|
|
230
232
|
Profiler.EndSample();
|
|
231
233
|
NextState();
|
package/Runtime/AmaGDK.cs
CHANGED
|
@@ -17,7 +17,7 @@ namespace Amanotes.Core
|
|
|
17
17
|
{
|
|
18
18
|
public partial class AmaGDK : MonoBehaviour
|
|
19
19
|
{
|
|
20
|
-
public const string VERSION = "0.2.
|
|
20
|
+
public const string VERSION = "0.2.70";
|
|
21
21
|
|
|
22
22
|
internal static Status _status = Status.None;
|
|
23
23
|
private static ConfigAsset _config = null;
|
|
@@ -176,7 +176,7 @@ namespace Amanotes.Core
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
var startTime = Time.realtimeSinceStartup;
|
|
179
|
-
var sb =
|
|
179
|
+
var sb = GDKPool.GetStringBuilder();
|
|
180
180
|
|
|
181
181
|
InitModules();
|
|
182
182
|
|
|
@@ -211,6 +211,7 @@ namespace Amanotes.Core
|
|
|
211
211
|
|
|
212
212
|
sb.Append($"\nMapping UserId: {User.UserId}\n");
|
|
213
213
|
Debug.Log($"AmaGDK v{VERSION} | {READY} in {initDuration:#0.00}s\n\n{sb}");
|
|
214
|
+
GDKPool.Return(sb);
|
|
214
215
|
}
|
|
215
216
|
|
|
216
217
|
private void ConfigGeoLocation()
|
|
@@ -354,6 +355,7 @@ namespace Amanotes.Core
|
|
|
354
355
|
public const string IRONSOURCE = "IronSource";
|
|
355
356
|
public const string MAX = "Max";
|
|
356
357
|
public const string REVENUECAT = "RevenueCat";
|
|
358
|
+
public const string SQLITE_ANALYTICS = "SqliteAnalytics";
|
|
357
359
|
}
|
|
358
360
|
}
|
|
359
361
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
using Amanotes.Core.Internal;
|
|
1
2
|
using System;
|
|
2
3
|
using System.Collections.Generic;
|
|
3
4
|
using System.Linq;
|
|
@@ -82,14 +83,15 @@ namespace Amanotes.Core
|
|
|
82
83
|
|
|
83
84
|
internal void ValidateParams(string eventName, Dictionary<string, object> eventParams)
|
|
84
85
|
{
|
|
85
|
-
|
|
86
|
+
var logBuilder = GDKPool.GetStringBuilder();
|
|
87
|
+
|
|
86
88
|
logBuilder.AppendLine($"Analytics quality violation found for event <{eventName}>");
|
|
87
|
-
|
|
88
|
-
HashSet<string> checkedParameters =
|
|
89
|
+
var isValid = true;
|
|
90
|
+
HashSet<string> checkedParameters = GDKPool.GetHashSet();
|
|
89
91
|
|
|
90
92
|
foreach (var kvp in DicParam)
|
|
91
93
|
{
|
|
92
|
-
if (!eventParams.
|
|
94
|
+
if (!eventParams.TryGetValue(kvp.Key, out object paramValue))
|
|
93
95
|
{
|
|
94
96
|
if (!kvp.Value.isOptional)
|
|
95
97
|
{
|
|
@@ -99,8 +101,6 @@ namespace Amanotes.Core
|
|
|
99
101
|
continue;
|
|
100
102
|
}
|
|
101
103
|
|
|
102
|
-
object paramValue = eventParams[kvp.Key];
|
|
103
|
-
|
|
104
104
|
if (!ValidateParamType(paramValue, kvp.Value.type))
|
|
105
105
|
{
|
|
106
106
|
isValid = false;
|
|
@@ -117,8 +117,11 @@ namespace Amanotes.Core
|
|
|
117
117
|
isValid = false;
|
|
118
118
|
logBuilder.AppendLine($"[+] {parameter.Key}");
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
|
|
121
121
|
if (!isValid) LogWarningOnce(logBuilder.ToString());
|
|
122
|
+
|
|
123
|
+
GDKPool.Return(logBuilder);
|
|
124
|
+
GDKPool.Return(checkedParameters);
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
private bool ValidateParamType(object paramValue, ParamType paramType)
|
|
@@ -179,7 +182,7 @@ namespace Amanotes.Core
|
|
|
179
182
|
[ContextMenu("Validate Unique EventNames")]
|
|
180
183
|
private void ValidateUniqueEventNames()
|
|
181
184
|
{
|
|
182
|
-
HashSet<string> eventNames =
|
|
185
|
+
HashSet<string> eventNames = GDKPool.GetHashSet();
|
|
183
186
|
|
|
184
187
|
lstEvent = lstEvent.OrderBy(evt => evt.eventName).ToList();
|
|
185
188
|
|
|
@@ -189,7 +192,7 @@ namespace Amanotes.Core
|
|
|
189
192
|
|
|
190
193
|
if (!eventNames.Add(eventQuality.eventName)) Debug.LogWarning($"Duplicate event name found: {eventQuality.eventName}. Event names must be unique.");
|
|
191
194
|
|
|
192
|
-
HashSet<string> paramNames =
|
|
195
|
+
HashSet<string> paramNames = GDKPool.GetHashSet();
|
|
193
196
|
|
|
194
197
|
eventQuality.lstParam = eventQuality.lstParam.OrderBy(param => param.paramName).ToList();
|
|
195
198
|
|
|
@@ -199,7 +202,11 @@ namespace Amanotes.Core
|
|
|
199
202
|
|
|
200
203
|
if (!paramNames.Add(param.paramName)) Debug.LogWarning($"Duplicate parameter name found in event {eventQuality.eventName}: {param.paramName}. Parameter names must be unique within an event.");
|
|
201
204
|
}
|
|
205
|
+
|
|
206
|
+
GDKPool.Return(paramNames);
|
|
202
207
|
}
|
|
208
|
+
|
|
209
|
+
GDKPool.Return(eventNames);
|
|
203
210
|
EditorUtility.SetDirty(this);
|
|
204
211
|
}
|
|
205
212
|
#endif
|
|
@@ -86,15 +86,13 @@ namespace Amanotes.Core
|
|
|
86
86
|
|
|
87
87
|
private void OnAudioDeviceAdded(string param)
|
|
88
88
|
{
|
|
89
|
-
if (string.IsNullOrEmpty(param))
|
|
90
|
-
return;
|
|
89
|
+
if (string.IsNullOrEmpty(param)) return;
|
|
91
90
|
onChanged?.Invoke(param);
|
|
92
91
|
}
|
|
93
92
|
|
|
94
93
|
private void OnAudioDeviceRemoved(string param)
|
|
95
94
|
{
|
|
96
|
-
if (string.IsNullOrEmpty(param))
|
|
97
|
-
return;
|
|
95
|
+
if (string.IsNullOrEmpty(param)) return;
|
|
98
96
|
onChanged?.Invoke(param);
|
|
99
97
|
}
|
|
100
98
|
|
|
@@ -170,15 +168,18 @@ namespace Amanotes.Core
|
|
|
170
168
|
}
|
|
171
169
|
|
|
172
170
|
StringBuilder sb = null;
|
|
173
|
-
|
|
174
|
-
for (int i = 0; i < str.Length; i++)
|
|
171
|
+
for (var i = 0; i < str.Length; i++)
|
|
175
172
|
{
|
|
176
173
|
char ch = str[i];
|
|
177
174
|
|
|
178
175
|
if (char.IsSurrogate(ch))
|
|
179
176
|
{
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
if (sb == null)
|
|
178
|
+
{
|
|
179
|
+
sb = GDKPool.GetStringBuilder();
|
|
180
|
+
sb.Append(str, 0, i);
|
|
181
|
+
}
|
|
182
|
+
|
|
182
183
|
sb.Append(replacementCharacter);
|
|
183
184
|
|
|
184
185
|
// If there is a high+low surrogate, skip the low surrogate
|
|
@@ -187,13 +188,13 @@ namespace Amanotes.Core
|
|
|
187
188
|
i++;
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
|
-
else
|
|
191
|
+
else
|
|
191
192
|
{
|
|
192
|
-
sb
|
|
193
|
+
sb?.Append(ch);
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
|
-
|
|
196
|
-
return sb == null ? str :
|
|
196
|
+
|
|
197
|
+
return sb == null ? str : GDKPool.ReturnString(sb);
|
|
197
198
|
}
|
|
198
199
|
}
|
|
199
200
|
|
package/Runtime/Core/GDKPool.cs
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
using System;
|
|
1
2
|
using System.Collections.Concurrent;
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.Text;
|
|
2
5
|
|
|
3
6
|
namespace Amanotes.Core.Internal
|
|
4
7
|
{
|
|
@@ -6,32 +9,95 @@ namespace Amanotes.Core.Internal
|
|
|
6
9
|
{
|
|
7
10
|
void Reset();
|
|
8
11
|
}
|
|
9
|
-
|
|
10
|
-
public class GDKPool
|
|
12
|
+
|
|
13
|
+
public static class GDKPool
|
|
11
14
|
{
|
|
12
|
-
|
|
15
|
+
internal class Pool<T> where T : new()
|
|
16
|
+
{
|
|
17
|
+
private readonly ConcurrentQueue<T> _pool;
|
|
18
|
+
public Pool(int initialCapacity = 4)
|
|
19
|
+
{
|
|
20
|
+
_pool = new ConcurrentQueue<T>();
|
|
21
|
+
for (var i = 0; i < initialCapacity; i++)
|
|
22
|
+
{
|
|
23
|
+
_pool.Enqueue(new T());
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public Pool(int initialCapacity, Func<T> newT)
|
|
28
|
+
{
|
|
29
|
+
_pool = new ConcurrentQueue<T>();
|
|
30
|
+
for (var i = 0; i < initialCapacity; i++)
|
|
31
|
+
{
|
|
32
|
+
_pool.Enqueue(newT());
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public T Get()
|
|
37
|
+
{
|
|
38
|
+
if (!_pool.TryDequeue(out var obj)) return new T();
|
|
39
|
+
if (obj is IPoolItem poolItem) poolItem.Reset();
|
|
40
|
+
return obj;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public void Return(T obj)
|
|
44
|
+
{
|
|
45
|
+
_pool.Enqueue(obj);
|
|
46
|
+
}
|
|
13
47
|
|
|
14
|
-
|
|
48
|
+
public int Count => _pool.Count;
|
|
49
|
+
}
|
|
50
|
+
private static readonly Pool<StringBuilder> sbPool1KB = new Pool<StringBuilder>(8, () => new StringBuilder(1024));
|
|
51
|
+
private static readonly Pool<StringBuilder> sbPool8KB = new Pool<StringBuilder>(8, () => new StringBuilder(8*1024));
|
|
52
|
+
private static readonly Pool<HashSet<string>> hashsetPool = new Pool<HashSet<string>>(4);
|
|
53
|
+
|
|
54
|
+
public static StringBuilder GetStringBuilder(int capacityInKb = 1)
|
|
55
|
+
{
|
|
56
|
+
StringBuilder result = capacityInKb <= 1 ? sbPool1KB.Get() : sbPool8KB.Get();
|
|
57
|
+
result.Clear();
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public static HashSet<string> GetHashSet()
|
|
62
|
+
{
|
|
63
|
+
HashSet<string> result = hashsetPool.Get();
|
|
64
|
+
result.Clear();
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public static string ReturnString(StringBuilder sb)
|
|
15
69
|
{
|
|
16
|
-
|
|
17
|
-
|
|
70
|
+
if (sb == null) return null;
|
|
71
|
+
var result = sb.ToString();
|
|
72
|
+
Return(sb);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public static void Return(StringBuilder sb)
|
|
77
|
+
{
|
|
78
|
+
if (sb == null) return;
|
|
79
|
+
int capacity = sb.Capacity;
|
|
80
|
+
|
|
81
|
+
if (capacity == 1024)
|
|
18
82
|
{
|
|
19
|
-
|
|
83
|
+
sbPool1KB.Return(sb);
|
|
84
|
+
return;
|
|
20
85
|
}
|
|
86
|
+
|
|
87
|
+
sbPool8KB.Return(sb);
|
|
21
88
|
}
|
|
22
|
-
|
|
23
|
-
public
|
|
89
|
+
|
|
90
|
+
public static void Return(HashSet<string> hashset)
|
|
24
91
|
{
|
|
25
|
-
if (
|
|
26
|
-
|
|
27
|
-
return obj;
|
|
92
|
+
if (hashset == null) return;
|
|
93
|
+
hashsetPool.Return(hashset);
|
|
28
94
|
}
|
|
29
|
-
|
|
30
|
-
public void
|
|
95
|
+
|
|
96
|
+
public static void ReturnAndNullize(ref HashSet<string> hashset)
|
|
31
97
|
{
|
|
32
|
-
|
|
98
|
+
if (hashset == null) return;
|
|
99
|
+
hashsetPool.Return(hashset);
|
|
100
|
+
hashset = null;
|
|
33
101
|
}
|
|
34
|
-
|
|
35
|
-
public int Count => _pool.Count;
|
|
36
102
|
}
|
|
37
103
|
}
|
|
@@ -68,16 +68,13 @@ namespace Amanotes.Core.Internal
|
|
|
68
68
|
{
|
|
69
69
|
public static Action<string> logNonfatalErrorHook = null;
|
|
70
70
|
private static readonly HashSet<string> nonFatalDict = new HashSet<string>();
|
|
71
|
-
|
|
72
|
-
public static readonly StringBuilder tmpWarningSB = new StringBuilder();
|
|
73
71
|
public static readonly HashSet<string> logWarningDict = new HashSet<string>();
|
|
74
72
|
|
|
75
73
|
public static void LogWarningOnce(string message, string key = null)
|
|
76
74
|
{
|
|
77
75
|
if (Config.common.logLevel < LogLevel.Warning) return;
|
|
78
76
|
if (string.IsNullOrEmpty(key)) key = message;
|
|
79
|
-
if (logWarningDict.
|
|
80
|
-
logWarningDict.Add(key);
|
|
77
|
+
if (!logWarningDict.Add(key)) return;
|
|
81
78
|
Debug.LogWarning($"AmaGDK {message}");
|
|
82
79
|
}
|
|
83
80
|
public static void LogWarning(string message)
|
|
@@ -133,7 +130,7 @@ namespace Amanotes.Core.Internal
|
|
|
133
130
|
}
|
|
134
131
|
|
|
135
132
|
AmaGDK[] result = Resources.FindObjectsOfTypeAll<AmaGDK>();
|
|
136
|
-
for (
|
|
133
|
+
for (var i = 0; i < result.Length; i++)
|
|
137
134
|
{
|
|
138
135
|
if (result[i] == null) continue;
|
|
139
136
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
using System;
|
|
2
2
|
using System.Collections;
|
|
3
|
-
using System.Collections.Concurrent;
|
|
4
3
|
using System.Collections.Generic;
|
|
5
4
|
using System.IO;
|
|
6
5
|
using System.Linq;
|
|
@@ -15,8 +14,6 @@ namespace Amanotes.Core.Internal
|
|
|
15
14
|
{
|
|
16
15
|
public static partial class GDKUtils
|
|
17
16
|
{
|
|
18
|
-
|
|
19
|
-
|
|
20
17
|
public static bool IsFromTemplate(string formattedString, string template)
|
|
21
18
|
{
|
|
22
19
|
// Split the original template into segments based on the positions of placeholders
|
|
@@ -271,7 +268,7 @@ namespace Amanotes.Core.Internal
|
|
|
271
268
|
|
|
272
269
|
public static void ClearCacheData()
|
|
273
270
|
{
|
|
274
|
-
var sb =
|
|
271
|
+
var sb = GDKPool.GetStringBuilder();
|
|
275
272
|
sb.AppendLine("[AmaGDK] All cached data & stats cleared");
|
|
276
273
|
|
|
277
274
|
if (!Directory.Exists(basePath))
|
|
@@ -408,16 +405,16 @@ namespace Amanotes.Core.Internal
|
|
|
408
405
|
return DictionaryToJson(new Dictionary<string, object>
|
|
409
406
|
{ { key, value } });
|
|
410
407
|
}
|
|
411
|
-
|
|
408
|
+
|
|
412
409
|
public static string DictionaryToJson(IDictionary inputDict, bool format = false, bool checkJsonInString = true)
|
|
413
410
|
{
|
|
414
411
|
if (inputDict == null) return "{}";
|
|
415
412
|
|
|
416
413
|
Profiler.BeginSample("AmaGDK.JsonUtils.DictionaryToJson()");
|
|
417
|
-
var jsonSb =
|
|
414
|
+
var jsonSb = GDKPool.GetStringBuilder(8);
|
|
418
415
|
jsonSb.Append("{");
|
|
419
416
|
bool isFirstElement = true;
|
|
420
|
-
|
|
417
|
+
|
|
421
418
|
foreach (DictionaryEntry entry in inputDict)
|
|
422
419
|
{
|
|
423
420
|
if (entry.Key == null || string.IsNullOrEmpty(entry.Key.ToString())) continue;
|
|
@@ -432,9 +429,9 @@ namespace Amanotes.Core.Internal
|
|
|
432
429
|
jsonSb.AppendFormat("{0}\"{1}\":", format ? "\n" : "", key);
|
|
433
430
|
AppendJsonValue(ref jsonSb, key, value, format, checkJsonInString);
|
|
434
431
|
}
|
|
435
|
-
|
|
432
|
+
|
|
436
433
|
jsonSb.AppendFormat("{0}{1}", format ? "\n" : "", "}");
|
|
437
|
-
|
|
434
|
+
var result = GDKPool.ReturnString(jsonSb);
|
|
438
435
|
Profiler.EndSample();
|
|
439
436
|
|
|
440
437
|
return result;
|
|
@@ -470,7 +467,7 @@ namespace Amanotes.Core.Internal
|
|
|
470
467
|
|
|
471
468
|
if (value is string)
|
|
472
469
|
{
|
|
473
|
-
|
|
470
|
+
var s = value.ToString();
|
|
474
471
|
if (checkJsonInString)
|
|
475
472
|
{
|
|
476
473
|
if (s.StartsWith("{") && s.EndsWith("}"))
|
|
@@ -484,7 +481,9 @@ namespace Amanotes.Core.Internal
|
|
|
484
481
|
return;
|
|
485
482
|
}
|
|
486
483
|
}
|
|
487
|
-
jsonSb.Append($"\"
|
|
484
|
+
jsonSb.Append($"\"");
|
|
485
|
+
AppendEscapeJsonString(jsonSb, s);
|
|
486
|
+
jsonSb.Append($"\"");
|
|
488
487
|
return;
|
|
489
488
|
}
|
|
490
489
|
|
|
@@ -521,81 +520,33 @@ namespace Amanotes.Core.Internal
|
|
|
521
520
|
/// </summary>
|
|
522
521
|
/// <param name="input">The input string to be escaped.</param>
|
|
523
522
|
/// <returns>The escaped string.</returns>
|
|
524
|
-
|
|
523
|
+
private static readonly Dictionary<char, string> escapeSequences = new Dictionary<char, string>
|
|
524
|
+
{
|
|
525
|
+
{ '\"', "\\\"" },
|
|
526
|
+
{ '\\', @"\\" },
|
|
527
|
+
{ '\b', "\\b" },
|
|
528
|
+
{ '\f', "\\f" },
|
|
529
|
+
{ '\n', "\\n" },
|
|
530
|
+
{ '\r', "\\r" },
|
|
531
|
+
{ '\t', "\\t" }
|
|
532
|
+
};
|
|
533
|
+
public static void AppendEscapeJsonString(StringBuilder sb, string input)
|
|
525
534
|
{
|
|
526
|
-
var sb = new StringBuilder();
|
|
527
535
|
foreach (char c in input)
|
|
528
536
|
{
|
|
529
|
-
|
|
537
|
+
if (escapeSequences.TryGetValue(c, out var escapedValue))
|
|
538
|
+
{
|
|
539
|
+
sb.Append(escapedValue);
|
|
540
|
+
}
|
|
541
|
+
else if (c < 0x20 || char.IsSurrogate(c))
|
|
530
542
|
{
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
case '\r': sb.Append("\\r"); break;
|
|
537
|
-
case '\t': sb.Append("\\t"); break;
|
|
538
|
-
default:
|
|
539
|
-
if (c < 0x20)
|
|
540
|
-
{
|
|
541
|
-
// Encode as \uXXXX for control characters
|
|
542
|
-
sb.Append("\\u" + ((int)c).ToString("X4"));
|
|
543
|
-
}
|
|
544
|
-
else if (char.IsSurrogate(c))
|
|
545
|
-
{
|
|
546
|
-
// Handle surrogate pairs
|
|
547
|
-
if (char.IsHighSurrogate(c))
|
|
548
|
-
{
|
|
549
|
-
sb.Append("\\u" + ((int)c).ToString("X4"));
|
|
550
|
-
}
|
|
551
|
-
else if (char.IsLowSurrogate(c))
|
|
552
|
-
{
|
|
553
|
-
sb.Append("\\u" + ((int)c).ToString("X4"));
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
else
|
|
557
|
-
{
|
|
558
|
-
// Keep characters as is if they are in the UTF-8 range
|
|
559
|
-
sb.Append(c);
|
|
560
|
-
}
|
|
561
|
-
break;
|
|
543
|
+
sb.AppendFormat("\\u{0:X4}", (int)c);
|
|
544
|
+
}
|
|
545
|
+
else
|
|
546
|
+
{
|
|
547
|
+
sb.Append(c);
|
|
562
548
|
}
|
|
563
549
|
}
|
|
564
|
-
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
//public static T[] FromJsonToArray<T>(string json)
|
|
569
|
-
//{
|
|
570
|
-
// if (!json.StartsWith("{\"items\":"))
|
|
571
|
-
// {
|
|
572
|
-
// json = $"{{\"items\":{json}}}";
|
|
573
|
-
// }
|
|
574
|
-
// Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
|
|
575
|
-
// return wrapper.items;
|
|
576
|
-
//}
|
|
577
|
-
|
|
578
|
-
//public static T FromJsonToObject<T>(string json)
|
|
579
|
-
//{
|
|
580
|
-
// return JsonUtility.FromJson<T>(json);
|
|
581
|
-
//}
|
|
582
|
-
|
|
583
|
-
//public static string ToJson<T>(T[] array)
|
|
584
|
-
//{
|
|
585
|
-
// Wrapper<T> wrapper = new Wrapper<T>();
|
|
586
|
-
// wrapper.items = array;
|
|
587
|
-
// return JsonUtility.ToJson(wrapper);
|
|
588
|
-
//}
|
|
589
|
-
|
|
590
|
-
//public static string ToJson<T>(T obj)
|
|
591
|
-
//{
|
|
592
|
-
// return JsonUtility.ToJson(obj);
|
|
593
|
-
//}
|
|
594
|
-
|
|
595
|
-
//[Serializable]
|
|
596
|
-
//private class Wrapper<T>
|
|
597
|
-
//{
|
|
598
|
-
// public T[] items;
|
|
599
|
-
//}
|
|
550
|
+
}
|
|
600
551
|
}
|
|
601
552
|
}
|