com.amanotes.gdk 0.2.71 → 0.2.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +96 -88
  2. package/Editor/AmaGDKEditor.cs +1 -1
  3. package/Editor/EmbedRemoteConfigAssetInspector.cs +1 -1
  4. package/Editor/Extra/GDKCIBuildCommand.cs +2 -16
  5. package/Extra/AmaGDKInstaller.unitypackage +0 -0
  6. package/Extra/CheckDiskSpace.unitypackage +0 -0
  7. package/Extra/Consent.unitypackage +0 -0
  8. package/Extra/ForceUpdate.unitypackage +0 -0
  9. package/Extra/LegacyGDKUpdateHelper.unitypackage +0 -0
  10. package/Extra/PostProcessor.unitypackage +0 -0
  11. package/Packages/AmaGDKConfig.unitypackage +0 -0
  12. package/Packages/AmaGDKExample.unitypackage +0 -0
  13. package/Packages/AmaGDKTest.unitypackage +0 -0
  14. package/Packages/AppsFlyerAdapter.PurchaseConnector.unitypackage +0 -0
  15. package/Packages/AppsFlyerAdapter.unitypackage +0 -0
  16. package/Packages/FirebaseAnalyticsAdapter.unitypackage +0 -0
  17. package/Packages/FirebaseRemoteConfigAdapter.unitypackage +0 -0
  18. package/Packages/IronSourceAdapter.unitypackage +0 -0
  19. package/Packages/MaxAdNetworkAdapter.unitypackage +0 -0
  20. package/Packages/RevenueCatAdapter.unitypackage +0 -0
  21. package/Packages/SqliteAnalyticsAdapter.unitypackage +0 -0
  22. package/Runtime/Ad/AdExtension.cs +2 -1
  23. package/Runtime/Ad/AdLogic.cs +1 -1
  24. package/Runtime/Ad/AmaGDK.Ads.cs +1 -1
  25. package/Runtime/AmaGDK.Adapters.cs +1 -1
  26. package/Runtime/AmaGDK.Analytics.cs +17 -30
  27. package/Runtime/AmaGDK.Config.cs +1 -7
  28. package/Runtime/AmaGDK.Consent.cs +9 -8
  29. package/Runtime/AmaGDK.Context.cs +1 -1
  30. package/Runtime/AmaGDK.Device.cs +3 -2
  31. package/Runtime/AmaGDK.IAP.cs +1 -1
  32. package/Runtime/AmaGDK.RemoteConfig.cs +2 -2
  33. package/Runtime/AmaGDK.Singleton.cs +1 -1
  34. package/Runtime/AmaGDK.UserProfile.cs +12 -11
  35. package/Runtime/AmaGDK.asmdef +1 -1
  36. package/Runtime/AmaGDK.cs +7 -7
  37. package/Runtime/AnalyticQualityAsset.cs +5 -6
  38. package/Runtime/AudioToolkit/AmaGDK.Audio.cs +3 -2
  39. package/Runtime/AudioToolkit/Plugins/AudioDeviceDetector.cs +2 -2
  40. package/Runtime/Core/GDKDebug.cs +97 -0
  41. package/Runtime/Core/GDKDebug.cs.meta +3 -0
  42. package/Runtime/Core/GDKPool.cs +56 -337
  43. package/Runtime/Core/GDKRoutine.cs +3 -1
  44. package/Runtime/Core/GDKSemVer.cs +1 -1
  45. package/Runtime/Core/GDKString.cs +197 -0
  46. package/Runtime/Core/GDKString.cs.meta +3 -0
  47. package/Runtime/EmbedRemoteConfigAsset.cs +2 -1
  48. package/Runtime/Fps/AmaFPS.Utils.cs +1 -1
  49. package/Runtime/Fps/AmaFPS.cs +1 -1
  50. package/Runtime/Fps/AmaFPSVisualizer.cs +1 -1
  51. package/Runtime/Fps/FrameRecorder.cs +1 -1
  52. package/Runtime/GDKAudio/GDKAudio.cs +11 -8
  53. package/Runtime/Internal/AmaGDK.Internal.cs +22 -33
  54. package/Runtime/Internal/AmaGDK.Utils.cs +4 -4
  55. package/Runtime/Internal/AmaGDK.WebUtils.cs +1 -1
  56. package/Runtime/Internal/GDKGeoLocationcs.cs +2 -1
  57. package/Runtime/Internal/GDKServerTime.cs +2 -1
  58. package/Runtime/Klavar/KlavarContainer.cs +4 -4
  59. package/Runtime/UserProfile/Plugins/Android/AdvertisingIdFetcher.cs +1 -1
  60. package/Runtime/Utils/GDKUtils.cs +1 -1
  61. package/package.json +1 -1
@@ -1,385 +1,104 @@
1
- using System;
1
+ using System;
2
2
  using System.Collections.Concurrent;
3
3
  using System.Collections.Generic;
4
- using System.Reflection;
5
4
  using System.Text;
6
- using Unity.Collections.LowLevel.Unsafe;
7
- using UnityEngine;
8
- using UnityEngine.Assertions;
9
- using UnityEngine.Profiling;
5
+
6
+ using static Amanotes.Core.GDKDebug;
10
7
  namespace Amanotes.Core.Internal
11
8
  {
12
- internal static class GDKPoolExtension
9
+ public interface IPoolItem
13
10
  {
14
- internal static T Pop<T>(this List<T> list)
15
- {
16
- if (list == null || list.Count == 0) return default;
17
-
18
- T result = list[list.Count - 1];
19
- list.RemoveAt(list.Count - 1);
20
- return result;
21
- }
22
- }
23
-
24
- public static partial class GDKPool // TypeHandler
25
- {
26
- private const int STRING_BUILDER_DEFAULT_LEN = 64;
27
- private static readonly Dictionary<Type, object> typeHandlerMap = new Dictionary<Type, object>
28
- {
29
- { typeof(StringBuilder), new TypeHandler<StringBuilder>(() => new StringBuilder(), h => h.Clear()) },
30
- { typeof(HashSet<string>), new TypeHandler<HashSet<string>>(() => new HashSet<string>(), h => h.Clear()) },
31
- { typeof(Dictionary<string, object>), new TypeHandler<Dictionary<string, object>>(() => new Dictionary<string, object>(), d => d.Clear()) }
32
- };
33
-
34
- public static TypeHandler<T> GetTypeHandler<T>() where T : class
35
- {
36
- return typeHandlerMap.TryGetValue(typeof(T), out object result)
37
- ? UnsafeUtility.As<object, TypeHandler<T>>(ref result)
38
- : null;
39
- }
40
-
41
- public static TypeHandler<T> AddTypeHandler<T>(Func<T> newT, Action<T> resetT = null) where T : class
42
- {
43
- if (typeof(IPoolItem).IsAssignableFrom(typeof(T)))
44
- {
45
- if (resetT != null) Debug.LogWarning("Unsupported custom resetT() when T: IPoolItem!");
46
- resetT = item => { (item as IPoolItem)?.Reset(); };
47
- }
48
-
49
- var result = new TypeHandler<T>(newT, resetT);
50
- typeHandlerMap.Add(typeof(T), result);
51
- return result;
52
- }
53
- public static TypeHandler<T> AddTypeHandler<T>(Action<T> resetT = null) where T : class, new()
54
- {
55
- return AddTypeHandler(() => new T(), resetT);
56
- }
57
- public class TypeHandler<T> where T : class
58
- {
59
- public readonly Func<T> newT;
60
- public readonly Action<T> resetT;
61
-
62
- public TypeHandler(Func<T> newT, Action<T> resetT)
63
- {
64
- this.newT = newT;
65
- this.resetT = resetT;
66
- }
67
- }
11
+ void Reset();
68
12
  }
69
13
 
70
- public static partial class GDKPool // Interface
71
- {
72
- public interface IPoolItem
73
- {
74
- void Reset();
75
- }
76
- public interface IPool<T> where T : class
77
- {
78
- int Count { get; } // Added to get the number of items currently in the pool
79
- T Take();
80
- void Return(T item);
81
- }
82
- public interface IPoolMap
83
- {
84
- IPool<T> GetPool<T>() where T : class;
85
- IPool<T> CreatePool<T>(TypeHandler<T> handler = null) where T : class;
86
- IPool<T> GetOrCreatePool<T>(TypeHandler<T> handler = null) where T : class;
87
- }
88
- }
89
- public static partial class GDKPool // POOLs
14
+ public static class GDKPool
90
15
  {
91
- internal abstract class BasePool<T, T1> : IPool<T>
92
- where T : class
93
- where T1 : new()
16
+ internal class Pool<T> where T : new()
94
17
  {
95
- internal readonly TypeHandler<T> handler;
96
- internal readonly T1 pool;
97
- protected BasePool(TypeHandler<T> handler)
18
+ private readonly ConcurrentQueue<T> _pool;
19
+ public Pool(int initialCapacity = 4)
98
20
  {
99
- pool = new T1();
100
- this.handler = handler;
101
- }
102
-
103
- public abstract T Take();
104
- public abstract void Return(T item);
105
- public abstract int Count { get; }
106
- }
107
- internal sealed class ListPool<T> : BasePool<T, List<T>> where T : class
108
- {
109
- public ListPool(TypeHandler<T> handler, int capacity) : base(handler)
110
- {
111
- for (var i = 0; i < capacity; i++)
21
+ _pool = new ConcurrentQueue<T>();
22
+ for (var i = 0; i < initialCapacity; i++)
112
23
  {
113
- Return(handler.newT());
24
+ _pool.Enqueue(new T());
114
25
  }
115
26
  }
116
- public override int Count => pool.Count;
117
-
118
- public override T Take()
119
- {
120
- if (pool.Count == 0) return handler.newT();
121
- T last = pool.Pop();
122
- handler.resetT?.Invoke(last); // Take from pool: Do Reset
123
- return last;
124
- }
125
-
126
- internal T TakeAt(int idx)
127
- {
128
- if (idx < 0 || idx >= pool.Count - 1) return Take();
129
-
130
- // swap last item to index
131
- T item = pool[idx];
132
- pool[idx] = pool.Pop();
133
- handler.resetT?.Invoke(item);
134
- return item;
135
- }
136
-
137
- public override void Return(T item)
138
- {
139
- if (item == null) return;
140
- pool.Add(item);
141
- }
142
- }
143
- internal sealed class ConcurrentPool<T> : BasePool<T, ConcurrentBag<T>> where T : class
144
- {
145
- public ConcurrentPool(TypeHandler<T> handler, int capacity) : base(handler)
27
+
28
+ public Pool(int initialCapacity, Func<T> newT)
146
29
  {
147
- for (var i = 0; i < capacity; i++)
30
+ _pool = new ConcurrentQueue<T>();
31
+ for (var i = 0; i < initialCapacity; i++)
148
32
  {
149
- Return(handler.newT());
33
+ _pool.Enqueue(newT());
150
34
  }
151
35
  }
152
-
153
- public override int Count => pool.Count;
154
-
155
- public override T Take()
156
- {
157
- if (!pool.TryTake(out T result)) return handler.newT();
158
- handler.resetT?.Invoke(result);
159
- return result;
160
- }
161
-
162
- public override void Return(T item)
163
- {
164
- if (item == null) return;
165
- pool.Add(item);
166
- }
167
- }
168
- }
169
-
170
- public static partial class GDKPool // POOL MAP
171
- {
172
- internal abstract class BasePoolMap<TDict> : IPoolMap where TDict : IDictionary<Type, object>, new()
173
- {
174
- internal readonly TDict map = new TDict();
175
-
176
- // IPoolMap
177
- public IPool<T> GetPool<T>() where T : class
178
- {
179
- return map.TryGetValue(typeof(T), out object result)
180
- ? UnsafeUtility.As<object, IPool<T>>(ref result)
181
- : null;
182
- }
183
-
184
- public IPool<T> CreatePool<T>(TypeHandler<T> handler = null) where T : class
36
+
37
+ public T Get()
185
38
  {
186
- return CreatePoolInternal(handler ?? GetTypeHandler<T>());
39
+ if (!_pool.TryDequeue(out var obj)) return new T();
40
+ if (obj is IPoolItem poolItem) poolItem.Reset();
41
+ return obj;
187
42
  }
188
43
 
189
- public IPool<T> GetOrCreatePool<T>(TypeHandler<T> handler = null) where T : class
44
+ public void Return(T obj)
190
45
  {
191
- return GetPool<T>() ?? CreatePoolInternal(handler ?? GetTypeHandler<T>());
46
+ _pool.Enqueue(obj);
192
47
  }
193
- internal abstract IPool<T> CreatePoolInternal<T>(TypeHandler<T> handler) where T : class;
194
- }
195
- internal class ListPoolMap : BasePoolMap<Dictionary<Type, object>>
196
- {
197
- internal override IPool<T> CreatePoolInternal<T>(TypeHandler<T> handler) where T : class
198
- {
199
- var result = new ListPool<T>(handler, 1);
200
- map.Add(typeof(T), result);
201
- return result;
202
- }
203
- }
204
- internal class ConcurrentPoolMap : BasePoolMap<ConcurrentDictionary<Type, object>>
205
- {
206
- internal override IPool<T> CreatePoolInternal<T>(TypeHandler<T> handler) where T : class
207
- {
208
- var result = new ConcurrentPool<T>(handler, 1);
209
- map.TryAdd(typeof(T), result);
210
- return result;
211
- }
212
- }
213
- }
214
-
215
- public static partial class GDKPool
216
- {
217
- private static readonly ListPoolMap mainPM = new ListPoolMap();
218
- private static readonly ConcurrentPoolMap threadPM = new ConcurrentPoolMap();
219
-
220
- // HashSet<T> support
221
- private static readonly ListPool<HashSet<string>> hPool; // cached reference for main-thread
222
- private static readonly ListPool<StringBuilder> sbPool;
223
-
224
- // StringBuilder support
225
- private static readonly ListPool<StringBuilder> fixedSBPool;
226
-
227
- // Dictionary support
228
- private static readonly ListPool<Dictionary<string, object>> dictPool;
229
48
 
230
- // SPECIAL APIs
231
- static GDKPool()
232
- {
233
- // Main-thread: Use fixed-length StringBuilder
234
- sbPool = (ListPool<StringBuilder>) mainPM.CreatePool<StringBuilder>();
235
- hPool = (ListPool<HashSet<string>>) mainPM.CreatePool<HashSet<string>>();
236
- dictPool = (ListPool<Dictionary<string, object>>)mainPM.CreatePool<Dictionary<string, object>>();
237
- fixedSBPool = new ListPool<StringBuilder>(new TypeHandler<StringBuilder>(null, sb => sb.Clear()), 0);
49
+ public int Count => _pool.Count;
238
50
  }
51
+ private static readonly Pool<StringBuilder> sbPool1KB = new Pool<StringBuilder>(8, () => new StringBuilder(1024));
52
+ private static readonly Pool<StringBuilder> sbPool8KB = new Pool<StringBuilder>(8, () => new StringBuilder(8*1024));
53
+ private static readonly Pool<HashSet<string>> hashsetPool = new Pool<HashSet<string>>(4);
239
54
 
240
- private static IPoolMap poolMap => GDKUtils.isOnMainThread ? mainPM : (IPoolMap)threadPM;
241
- internal static void ClearAndReset()
55
+ public static StringBuilder GetStringBuilder(int capacityInKb = 1)
242
56
  {
243
- // main thread
244
- mainPM.map.Clear();
245
- mainPM.map.Add(typeof(StringBuilder), sbPool);
246
- mainPM.map.Add(typeof(HashSet<string>), hPool);
247
- mainPM.map.Add(typeof(Dictionary<string, object>), dictPool);
248
-
249
- // other threads
250
- threadPM.map.Clear();
57
+ StringBuilder result = capacityInKb <= 1 ? sbPool1KB.Get() : sbPool8KB.Get();
58
+ result.Clear();
59
+ return result;
251
60
  }
252
-
253
- public static T Take<T>(bool autoCreatePool = true) where T : class, new()
61
+
62
+ public static HashSet<string> GetHashSet()
254
63
  {
255
- IPool<T> pool = poolMap.GetPool<T>() ?? CreatePool<T>();
256
- return pool.Take();
64
+ HashSet<string> result = hashsetPool.Get();
65
+ result.Clear();
66
+ return result;
257
67
  }
258
68
 
259
- public static T Take<T>(Action<T> resetT) where T : class, new()
69
+ public static string ReturnString(StringBuilder sb)
260
70
  {
261
- IPool<T> pool = poolMap.GetPool<T>() ?? CreatePool(() => new T(), resetT);
262
- return pool.Take();
71
+ if (sb == null) return null;
72
+ var result = sb.ToString();
73
+ Return(sb);
74
+ return result;
263
75
  }
264
76
 
265
- public static void Return<T>(T item) where T : class
77
+ public static void Return(StringBuilder sb)
266
78
  {
267
- if (typeof(T) == typeof(StringBuilder))
79
+ if (sb == null) return;
80
+ int capacity = sb.Capacity;
81
+
82
+ if (capacity == 1024)
268
83
  {
269
- StringBuilder sb = UnsafeUtility.As<T, StringBuilder>(ref item);
270
- if (sb.Capacity == sb.MaxCapacity)
271
- {
272
- fixedSBPool.Return(sb);
273
- return;
274
- }
84
+ sbPool1KB.Return(sb);
85
+ return;
275
86
  }
276
87
 
277
- poolMap.GetPool<T>()?.Return(item);
278
- }
279
-
280
- public static IPool<T> GetPool<T>(bool autoCreatePool = false) where T : class, new()
281
- {
282
- IPool<T> result = poolMap.GetPool<T>();
283
- if (result != null) return result;
284
- return autoCreatePool ? CreatePool<T>() : null;
285
- }
286
- private static IPool<T> TryCreatePoolUsingTypeHandler<T>() where T : class
287
- {
288
- TypeHandler<T> handler = GetTypeHandler<T>();
289
- return handler != null ? poolMap.CreatePool(handler) : null;
88
+ sbPool8KB.Return(sb);
290
89
  }
291
- public static IPool<T> CreatePool<T>(Func<T> newT, Action<T> resetT) where T : class
292
- {
293
- IPool<T> result = TryCreatePoolUsingTypeHandler<T>();
294
- if (result != null) return result;
295
- return poolMap.CreatePool(AddTypeHandler(newT, resetT));
296
- }
297
-
298
- public static IPool<T> CreatePool<T>(Action<T> resetT = null) where T : class, new()
299
- {
300
- IPool<T> result = TryCreatePoolUsingTypeHandler<T>();
301
- if (result != null) return result;
302
- return poolMap.CreatePool(AddTypeHandler(() => new T(), resetT));
303
- }
304
- public static HashSet<T> TakeHashSet<T>()
305
- {
306
- var result = Take<HashSet<T>>();
307
- return result ?? CreatePool<HashSet<T>>(h => h.Clear()).Take();
308
- }
309
- public static HashSet<string> TakeHashSet()
90
+
91
+ public static void Return(HashSet<string> hashset)
310
92
  {
311
- return GDKUtils.isOnMainThread ? hPool.Take() : TakeHashSet<string>();
93
+ if (hashset == null) return;
94
+ hashsetPool.Return(hashset);
312
95
  }
313
-
96
+
314
97
  public static void ReturnAndNullize(ref HashSet<string> hashset)
315
98
  {
316
99
  if (hashset == null) return;
317
- hashset.Clear();
318
- Return(hashset);
100
+ hashsetPool.Return(hashset);
319
101
  hashset = null;
320
102
  }
321
-
322
- public static StringBuilder TakeStringBuilder(int fixedLength = 0)
323
- {
324
- if (!GDKUtils.isOnMainThread)
325
- {
326
- if (fixedLength != 0) Logging.LogWarningOnce("Fixed length StringBuilder only work for Main Thread!");
327
- return Take<StringBuilder>();
328
- }
329
-
330
- if (fixedLength == 0) return Take<StringBuilder>();
331
-
332
- if (fixedSBPool.Count == 0) return new StringBuilder(fixedLength, fixedLength);
333
- List<StringBuilder> pool = fixedSBPool.pool;
334
- for (var i = 0; i < pool.Count; i++)
335
- {
336
- if (pool[i].Capacity != fixedLength) continue;
337
- return fixedSBPool.TakeAt(i);
338
- }
339
-
340
- return new StringBuilder(fixedLength, fixedLength);
341
- }
342
-
343
- private static FieldInfo sbStringValueField;
344
- private static readonly Dictionary<StringBuilder, string> internalSB = new Dictionary<StringBuilder, string>();
345
- public static string ReturnAndStringify(StringBuilder sb)
346
- {
347
- if (sb == null) return null;
348
-
349
- // if (GDKUtils.isOnMainThread && sb.Capacity == sb.MaxCapacity)
350
- // {
351
- // string str;
352
- // Profiler.BeginSample("GDKPool.ReturnAndStringify()");
353
- // {
354
- // if (!internalSB.TryGetValue(sb, out str))
355
- // {
356
- // sbStringValueField ??= typeof(StringBuilder)
357
- // .GetField("m_StringValue", BindingFlags.NonPublic | BindingFlags.Instance);
358
- //
359
- // str = (string)sbStringValueField?.GetValue(sb);
360
- // internalSB.Add(sb, str);
361
- // }
362
- //
363
- // fixedSBPool.Return(sb);
364
- // }
365
- // Profiler.EndSample();
366
- // return str;
367
- // }
368
-
369
- string result = null;
370
- Profiler.BeginSample("GDKPool.ReturnAndStringify()");
371
- {
372
- result = sb.ToString();
373
- sb.Clear();
374
- Return(sb);
375
- }
376
- Profiler.EndSample();
377
-
378
- return result;
379
- }
380
- public static Dictionary<string, object> TakeDictionary()
381
- {
382
- return GDKUtils.isOnMainThread ? dictPool.Take() : Take<Dictionary<string, object>>();
383
- }
384
103
  }
385
104
  }
@@ -1,6 +1,8 @@
1
1
  using System;
2
2
  using System.Collections;
3
3
  using UnityEngine;
4
+ using static Amanotes.Core.GDKDebug;
5
+
4
6
  namespace Amanotes.Core.Internal
5
7
  {
6
8
  public class GDKRoutine
@@ -59,7 +61,7 @@ namespace Amanotes.Core.Internal
59
61
  } catch (Exception ex)
60
62
  {
61
63
  status |= RoutineStatus.Stopped;
62
- if (exceptionHandler == null) Logging.LogError($"Exception caught in coroutine: {ex}");
64
+ if (exceptionHandler == null) LogError($"Exception caught in coroutine: {ex}");
63
65
  exceptionHandler?.Invoke(ex);
64
66
  yield break; // Stop executing the coroutine
65
67
  }
@@ -2,7 +2,7 @@
2
2
  using System.Collections.Generic;
3
3
  using System.Text.RegularExpressions;
4
4
  using UnityEngine.Profiling;
5
- using static Amanotes.Core.Internal.Logging;
5
+ using static Amanotes.Core.GDKDebug;
6
6
 
7
7
  namespace Amanotes.Core.Internal
8
8
  {
@@ -0,0 +1,197 @@
1
+ using System;
2
+ using UnityEngine;
3
+
4
+ namespace Amanotes.Core
5
+ {
6
+ public static class GDKStringExtension
7
+ {
8
+ internal static void Log(GDKString gdkStr, LogType logType, UnityEngine.Object context, Action<string, UnityEngine.Object> logFunc)
9
+ {
10
+ StackTraceLogType type = Application.GetStackTraceLogType(logType);
11
+ Application.SetStackTraceLogType(logType, StackTraceLogType.None);
12
+ {
13
+ logFunc(gdkStr.ToString(), context);
14
+ }
15
+ Application.SetStackTraceLogType(logType, type);
16
+ gdkStr.Clear();
17
+ }
18
+
19
+ public static void Log(this GDKString gdkStr, UnityEngine.Object context = null)
20
+ {
21
+ Log(gdkStr, LogType.Log, context, Debug.Log);
22
+ }
23
+
24
+ public static void LogWarning(this GDKString gdkStr, UnityEngine.Object context = null)
25
+ {
26
+ Log(gdkStr, LogType.Warning, context, Debug.LogWarning);
27
+ }
28
+
29
+ public static void LogError(this GDKString gdkStr, UnityEngine.Object context = null)
30
+ {
31
+ Log(gdkStr, LogType.Error, context, Debug.LogError);
32
+ }
33
+
34
+ private static readonly char[] DigitChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
35
+ internal static unsafe int Write(string s, int stIndex, ulong value, bool writePrefix = false, char prefix = '-')
36
+ {
37
+ fixed (char* ptr = s)
38
+ {
39
+ var idx = 0;
40
+ if (writePrefix)
41
+ {
42
+ ptr[stIndex] = prefix;
43
+ idx++;
44
+ }
45
+
46
+ if (value <= 9)
47
+ {
48
+ ptr[stIndex + idx] = DigitChars[value];
49
+ idx++;
50
+ return idx;
51
+ }
52
+
53
+ var len = (int)Math.Ceiling(Math.Log10(value));
54
+ int endIdx = stIndex + len - 1 + idx;
55
+ do
56
+ {
57
+ ptr[endIdx] = (char)('0' + value % 10);
58
+ endIdx--;
59
+ value /= 10;
60
+ } while (value > 0);
61
+
62
+ idx += len;
63
+ return idx;
64
+ }
65
+ }
66
+
67
+ internal static int WriteULong(this string s, int stIndex, ulong value)
68
+ {
69
+ return Write(s, stIndex, value);
70
+ }
71
+
72
+ internal static int WriteLong(this string s, int stIndex, long value)
73
+ {
74
+ return Write(s, stIndex, (ulong)(value < 0 ? -value : value), value < 0, '-');
75
+ }
76
+
77
+ internal static int WriteDouble(this string s, int stIndex, double value, int decimalPlaces = 4)
78
+ {
79
+ var integerPart = (ulong)value;
80
+ int counter = Write(s, stIndex, integerPart, value < 0);
81
+ if (decimalPlaces <= 0) return counter;
82
+
83
+ double fractionalPart = value - integerPart;
84
+ for (var i = 0; i < decimalPlaces; i++)
85
+ {
86
+ fractionalPart *= 10;
87
+ }
88
+
89
+ var fractionalInt = (ulong)(fractionalPart + 0.5);
90
+ counter += Write(s, stIndex + counter, fractionalInt, true, '.');
91
+ return counter;
92
+ }
93
+ }
94
+
95
+ public unsafe class GDKString
96
+ {
97
+ private readonly int _capacity;
98
+ private readonly string _str;
99
+ private int _length;
100
+
101
+ public GDKString(int capacity)
102
+ {
103
+ _capacity = capacity;
104
+ _str = new string('\0', capacity);
105
+ _length = 0;
106
+ }
107
+
108
+ public int Length => _length;
109
+
110
+ private GDKString SetLength(int value)
111
+ {
112
+ if (value < 0 || value > _capacity)
113
+ {
114
+ throw new ArgumentOutOfRangeException(nameof(value));
115
+ }
116
+
117
+ _length = value;
118
+ fixed (char* ptr = _str)
119
+ {
120
+ ptr[value] = '\0';
121
+ *(int*)((IntPtr)ptr - sizeof(int)) = _length;
122
+ }
123
+
124
+ return this;
125
+ }
126
+
127
+ public GDKString Append(string value)
128
+ {
129
+ return string.IsNullOrEmpty(value) ? this : WriteAt(_length, value);
130
+ }
131
+
132
+ public GDKString WriteAt(int stIdx, string value)
133
+ {
134
+ if (string.IsNullOrEmpty(value)) return this;
135
+
136
+ int vLength = value.Length;
137
+ if (stIdx + vLength >= _capacity)
138
+ {
139
+ throw new InvalidOperationException("Buffer overflow.");
140
+ }
141
+
142
+ // Calculate the number of bytes to copy (2 bytes per char)
143
+ fixed (char* srcPtr = value)
144
+ fixed (char* destPtr = _str)
145
+ {
146
+ // Use memcpy equivalent with pointers
147
+ char* destPos = destPtr + _length;
148
+ for (var i = 0; i < vLength; i++)
149
+ {
150
+ *(destPos + i) = *(srcPtr + i);
151
+ }
152
+ }
153
+
154
+ if (stIdx + vLength > _length) SetLength(_length + vLength);
155
+ return this;
156
+ }
157
+
158
+ public GDKString Append(int value)
159
+ {
160
+ int vLength = _str.WriteLong(Length, value);
161
+ return SetLength(_length + vLength);
162
+ }
163
+
164
+ public GDKString Append(uint value)
165
+ {
166
+ int vLength = _str.WriteULong(Length, value);
167
+ return SetLength(_length + vLength);
168
+ }
169
+
170
+ private const string TRUE = "True";
171
+ private const string FALSE = "False";
172
+ public GDKString Append(bool value)
173
+ {
174
+ Append(value ? TRUE : FALSE);
175
+ return this;
176
+ }
177
+
178
+ public GDKString Append(float value)
179
+ {
180
+ int vLength = _str.WriteDouble(Length, value);
181
+ return SetLength(_length + vLength);
182
+ }
183
+
184
+ public GDKString Append(double value)
185
+ {
186
+ int vLength = _str.WriteDouble(Length, value);
187
+ return SetLength(_length + vLength);
188
+ }
189
+
190
+ public GDKString Clear()
191
+ {
192
+ return SetLength(0);
193
+ }
194
+
195
+ public override string ToString() => _str;
196
+ }
197
+ }
@@ -0,0 +1,3 @@
1
+ fileFormatVersion: 2
2
+ guid: 1b832c4b2bab4b7d8f05c2d315eb6f85
3
+ timeCreated: 1724065190
@@ -1,6 +1,7 @@
1
1
  using System;
2
2
  using System.Linq;
3
3
  using UnityEngine;
4
+ using static Amanotes.Core.GDKDebug;
4
5
 
5
6
  namespace Amanotes.Core.Internal
6
7
  {
@@ -30,7 +31,7 @@ namespace Amanotes.Core.Internal
30
31
  {
31
32
  var config = configs?.FirstOrDefault(a => a.id == id);
32
33
  if (config == null)
33
- Logging.LogWarningOnce($"Not found embedded config <{id}>");
34
+ LogWarningOnce($"Not found embedded config <{id}>");
34
35
  return config;
35
36
  }
36
37