com.amanotes.gdk 0.2.81-alpha.13 → 0.2.81-alpha.17
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/Extra/ABLab.unitypackage +0 -0
- package/Extra/ABLab.unitypackage.meta +7 -0
- 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/AmaGDK.Ads.cs +9 -6
- package/Runtime/AmaGDK.Analytics.cs +22 -12
- package/Runtime/AmaGDK.IAP.cs +6 -5
- package/Runtime/AmaGDK.Mono.cs +19 -1
- package/Runtime/AmaGDK.RemoteConfig.cs +4 -2
- package/Runtime/AmaGDK.Singleton.cs +2 -1
- package/Runtime/AmaGDK.UserProfile.cs +2 -2
- package/Runtime/AmaGDK.asmdef +3 -1
- package/Runtime/AmaGDK.cs +52 -48
- package/Runtime/Consent/AmaGDK.Consent.cs +7 -6
- package/Runtime/Core/GDKDebug.cs +15 -1
- package/Runtime/Internal/AmaGDK.Utils.cs +1 -1
- package/Runtime/Internal/ForceQuitMonitor.cs +1 -1
- package/Runtime/Utils/GDKFileUtils.cs +240 -104
- package/package.json +30 -18
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/Runtime/Ad/AmaGDK.Ads.cs
CHANGED
|
@@ -3,7 +3,7 @@ using System.Collections;
|
|
|
3
3
|
using System.Collections.Generic;
|
|
4
4
|
using UnityEngine;
|
|
5
5
|
using Amanotes.Core.Internal;
|
|
6
|
-
|
|
6
|
+
using Cysharp.Threading.Tasks;
|
|
7
7
|
using static Amanotes.Core.GDKDebug;
|
|
8
8
|
using static Amanotes.Core.AmaGDK;
|
|
9
9
|
|
|
@@ -93,7 +93,7 @@ namespace Amanotes.Core
|
|
|
93
93
|
|
|
94
94
|
internal void Save()
|
|
95
95
|
{
|
|
96
|
-
this.SaveJsonToFile();
|
|
96
|
+
this.SaveJsonToFile(false);
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
|
|
@@ -108,8 +108,7 @@ namespace Amanotes.Core
|
|
|
108
108
|
public static bool allowAdRequest = true;
|
|
109
109
|
|
|
110
110
|
// internal use
|
|
111
|
-
|
|
112
|
-
internal static AdsData localData => _localData.Value;
|
|
111
|
+
internal static AdsData localData;
|
|
113
112
|
|
|
114
113
|
internal protected static AdShowContext context;
|
|
115
114
|
internal protected static AdAdapter _adapter;
|
|
@@ -154,14 +153,18 @@ namespace Amanotes.Core
|
|
|
154
153
|
|
|
155
154
|
public partial class Ads // Public
|
|
156
155
|
{
|
|
157
|
-
internal static
|
|
156
|
+
internal static async UniTask InitModule()
|
|
158
157
|
{
|
|
158
|
+
await UniTask.SwitchToThreadPool();
|
|
159
159
|
if (Adapter2.GetAllAdapter<AdAdapter>().Count > 1)
|
|
160
160
|
{
|
|
161
161
|
GDKUtils.ThrowExceptionIfEditor("Multiple AdAdapters is not supported!");
|
|
162
162
|
}
|
|
163
163
|
_adapter = Adapter2.GetAdapter<AdAdapter>();
|
|
164
|
-
|
|
164
|
+
if(_adapter != null)
|
|
165
|
+
{
|
|
166
|
+
localData = new AdsData().LoadJsonFromFile();
|
|
167
|
+
}
|
|
165
168
|
}
|
|
166
169
|
|
|
167
170
|
internal static void StartModule()
|
|
@@ -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 Cysharp.Threading.Tasks;
|
|
6
7
|
using UnityEngine;
|
|
7
8
|
using UnityEngine.Profiling;
|
|
8
9
|
using static Amanotes.Core.AmaGDK.Analytics;
|
|
@@ -130,12 +131,11 @@ namespace Amanotes.Core
|
|
|
130
131
|
if (Config.analytics.autoFlushEventDetail)
|
|
131
132
|
{
|
|
132
133
|
LogWarning("[Analytics] This function FlushEventDetails() is not supposed to be called manually!");
|
|
133
|
-
return;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
if (!localData._dirty) return;
|
|
137
137
|
localData._dirty = false;
|
|
138
|
-
localData.SaveJsonToFile();
|
|
138
|
+
localData.SaveJsonToFile(false);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
public static IEventParamsBuilder LogFunnelEvent(string eventName, string signature = "")
|
|
@@ -312,10 +312,7 @@ namespace Amanotes.Core
|
|
|
312
312
|
internal static readonly List<AnalyticsAdapter> listAdapters = new List<AnalyticsAdapter>();
|
|
313
313
|
internal static SessionStat sessionStat;
|
|
314
314
|
internal static readonly GDKPool.Pool<EventParams> epPool = new GDKPool.Pool<EventParams>(1);
|
|
315
|
-
|
|
316
|
-
private static readonly Lazy<AnalyticsData> _localData = new Lazy<AnalyticsData>(
|
|
317
|
-
() => new AnalyticsData().LoadJsonFromFile().BuildCache());
|
|
318
|
-
internal static AnalyticsData localData => _localData.Value;
|
|
315
|
+
internal static AnalyticsData localData;
|
|
319
316
|
|
|
320
317
|
internal static readonly Dictionary<string, string> reservedPrefixes = new Dictionary<string, string>()
|
|
321
318
|
{
|
|
@@ -359,14 +356,19 @@ namespace Amanotes.Core
|
|
|
359
356
|
"user_engagement"
|
|
360
357
|
};
|
|
361
358
|
|
|
362
|
-
internal static
|
|
359
|
+
internal static async UniTask InitModule()
|
|
363
360
|
{
|
|
361
|
+
await UniTask.SwitchToThreadPool();
|
|
364
362
|
if (Config.analytics.enableEventStat)
|
|
365
363
|
{
|
|
366
364
|
sessionStat = new SessionStat();
|
|
367
365
|
}
|
|
368
366
|
listAdapters.Clear();
|
|
369
367
|
listAdapters.AddRange(Adapter2.GetAllAdapter<AnalyticsAdapter>());
|
|
368
|
+
if (listAdapters.Count > 0)
|
|
369
|
+
{
|
|
370
|
+
localData = new AnalyticsData().LoadJsonFromFile().BuildCache();
|
|
371
|
+
}
|
|
370
372
|
}
|
|
371
373
|
|
|
372
374
|
internal static void StartModule()
|
|
@@ -648,7 +650,12 @@ namespace Amanotes.Core
|
|
|
648
650
|
internal static void PostPrepareEventProcess(EventParams eventData)
|
|
649
651
|
{
|
|
650
652
|
if (!eventData.parameters.ContainsKey("ama_device_id"))
|
|
651
|
-
|
|
653
|
+
{
|
|
654
|
+
if (!string.IsNullOrWhiteSpace(User.AmaDeviceId))
|
|
655
|
+
{
|
|
656
|
+
eventData.AddParam("ama_device_id", User.AmaDeviceId);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
652
659
|
}
|
|
653
660
|
|
|
654
661
|
internal static bool ShouldSendEvent(EventParams eventData)
|
|
@@ -715,10 +722,13 @@ namespace Amanotes.Core
|
|
|
715
722
|
{
|
|
716
723
|
sb.Append(eventNameToSend);
|
|
717
724
|
sb.Append("\t");
|
|
718
|
-
|
|
725
|
+
if (adapters != null && adapters.Count > 0)
|
|
719
726
|
{
|
|
720
|
-
|
|
721
|
-
|
|
727
|
+
for (var i = 0; i < adapters.Count; i++)
|
|
728
|
+
{
|
|
729
|
+
sb.Append(adapters[i]);
|
|
730
|
+
if (i < adapters.Count - 1) sb.Append(",");
|
|
731
|
+
}
|
|
722
732
|
}
|
|
723
733
|
sb.Append("\t");
|
|
724
734
|
sb.AppendLine(eventParamsInJSON);
|
|
@@ -843,7 +853,7 @@ namespace Amanotes.Core
|
|
|
843
853
|
if (!Config.analytics.autoFlushEventDetail) return;
|
|
844
854
|
if (!_dirty) return;
|
|
845
855
|
_dirty = false;
|
|
846
|
-
this.SaveJsonToFile();
|
|
856
|
+
this.SaveJsonToFile(false);
|
|
847
857
|
}
|
|
848
858
|
|
|
849
859
|
internal void UpdateMigrationLog()
|
package/Runtime/AmaGDK.IAP.cs
CHANGED
|
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|
|
4
4
|
using System.Globalization;
|
|
5
5
|
using UnityEngine;
|
|
6
6
|
using Amanotes.Core.Internal;
|
|
7
|
-
|
|
7
|
+
using Cysharp.Threading.Tasks;
|
|
8
8
|
using static Amanotes.Core.AmaGDK.IAP;
|
|
9
9
|
using static Amanotes.Core.GDKDebug;
|
|
10
10
|
|
|
@@ -176,12 +176,13 @@ namespace Amanotes.Core
|
|
|
176
176
|
|
|
177
177
|
private static bool IsModuleReady => _syncTaskTracker.HasCompleted && _getProductsTaskTracker.HasCompleted;
|
|
178
178
|
private static Action _onModuleReady;
|
|
179
|
-
internal static
|
|
179
|
+
internal static async UniTask InitModule()
|
|
180
180
|
{
|
|
181
|
+
await UniTask.SwitchToThreadPool();
|
|
181
182
|
_adapter = Adapter2.GetAdapter<IAPAdapter>();
|
|
182
|
-
if (_adapter == null)
|
|
183
|
+
if (_adapter == null)
|
|
184
|
+
return;
|
|
183
185
|
localData = new IAPData().LoadJsonFromFile();
|
|
184
|
-
return true;
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
internal static void StartModule()
|
|
@@ -281,7 +282,7 @@ namespace Amanotes.Core
|
|
|
281
282
|
subscriptionExpiredDate = _subscriptionExpiredDate?.ToString(DATE_FORMAT);
|
|
282
283
|
_unsubscribedDate = Adapter.GetUnsubscribedDate();
|
|
283
284
|
unsubscribedDate = _unsubscribedDate?.ToString(DATE_FORMAT);
|
|
284
|
-
this.SaveJsonToFile();
|
|
285
|
+
this.SaveJsonToFile(false);
|
|
285
286
|
}
|
|
286
287
|
}
|
|
287
288
|
}
|
package/Runtime/AmaGDK.Mono.cs
CHANGED
|
@@ -3,6 +3,7 @@ using System;
|
|
|
3
3
|
using System.Collections;
|
|
4
4
|
using System.Collections.Generic;
|
|
5
5
|
using System.Threading;
|
|
6
|
+
using Cysharp.Threading.Tasks;
|
|
6
7
|
using UnityEngine;
|
|
7
8
|
|
|
8
9
|
namespace Amanotes.Core
|
|
@@ -78,7 +79,18 @@ namespace Amanotes.Core.Internal
|
|
|
78
79
|
{
|
|
79
80
|
StartCoroutine(DelayCallRoutine(seconds, action));
|
|
80
81
|
}
|
|
81
|
-
|
|
82
|
+
|
|
83
|
+
public static async UniTask TimeoutTask(float timeoutInSecs, Func<bool> completeCheckFunc)
|
|
84
|
+
{
|
|
85
|
+
float time = Time.realtimeSinceStartup;
|
|
86
|
+
while (completeCheckFunc() == false)
|
|
87
|
+
{
|
|
88
|
+
await UniTask.Yield();
|
|
89
|
+
if (Time.realtimeSinceStartup - time > timeoutInSecs)
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
82
94
|
public static IEnumerator Timeout(float timeoutInSecs, Func<bool> completeCheckFunc)
|
|
83
95
|
{
|
|
84
96
|
float time = Time.realtimeSinceStartup;
|
|
@@ -88,6 +100,12 @@ namespace Amanotes.Core.Internal
|
|
|
88
100
|
if (Time.realtimeSinceStartup - time > timeoutInSecs) yield break;
|
|
89
101
|
}
|
|
90
102
|
}
|
|
103
|
+
|
|
104
|
+
private static async UniTask DelayCallRoutineTask(float seconds, Action callback)
|
|
105
|
+
{
|
|
106
|
+
await UniTask.Delay(TimeSpan.FromSeconds(seconds));
|
|
107
|
+
callback();
|
|
108
|
+
}
|
|
91
109
|
|
|
92
110
|
private static IEnumerator DelayCallRoutine(float seconds, Action callback)
|
|
93
111
|
{
|
|
@@ -5,6 +5,7 @@ using System.IO;
|
|
|
5
5
|
using System.Text;
|
|
6
6
|
using UnityEngine;
|
|
7
7
|
using Amanotes.Core.Internal;
|
|
8
|
+
using Cysharp.Threading.Tasks;
|
|
8
9
|
using UnityEngine.Profiling;
|
|
9
10
|
using UnityEngine.Serialization;
|
|
10
11
|
using static Amanotes.Core.GDKDebug;
|
|
@@ -173,8 +174,9 @@ namespace Amanotes.Core
|
|
|
173
174
|
actions[result ? 1 : 0]();
|
|
174
175
|
}
|
|
175
176
|
|
|
176
|
-
internal static
|
|
177
|
+
internal static async UniTask InitModule()
|
|
177
178
|
{
|
|
179
|
+
await UniTask.SwitchToThreadPool();
|
|
178
180
|
adapter = Adapter2.GetAdapter<RemoteConfigAdapter>();
|
|
179
181
|
}
|
|
180
182
|
|
|
@@ -235,7 +237,7 @@ namespace Amanotes.Core
|
|
|
235
237
|
}
|
|
236
238
|
|
|
237
239
|
string filePath = GDKFileUtils.GetPath(fileName);
|
|
238
|
-
GDKFileUtils.Save(filePath, sb.ToString());
|
|
240
|
+
GDKFileUtils.Save(filePath, sb.ToString(), false);
|
|
239
241
|
GDKPool.Return(sb);
|
|
240
242
|
|
|
241
243
|
Log($"[RemoteConfig] Saved remote config to {filePath}");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
using Amanotes.Core.Internal;
|
|
3
3
|
using System.Threading;
|
|
4
|
+
using Cysharp.Threading.Tasks;
|
|
4
5
|
using static Amanotes.Core.GDKDebug;
|
|
5
6
|
using static Amanotes.Core.Internal.Messsage;
|
|
6
7
|
|
|
@@ -23,7 +24,7 @@ namespace Amanotes.Core
|
|
|
23
24
|
mainThreadId = Thread.CurrentThread.ManagedThreadId;
|
|
24
25
|
DontDestroyOnLoad(this);
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
InitRoutine().Forget();
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -33,14 +33,14 @@ namespace Amanotes.Core
|
|
|
33
33
|
private bool _dirty = false;
|
|
34
34
|
private void Save()
|
|
35
35
|
{
|
|
36
|
-
this.SaveJsonToFile();
|
|
36
|
+
this.SaveJsonToFile(false);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
private void SaveIfDirty()
|
|
40
40
|
{
|
|
41
41
|
if (!_dirty) return;
|
|
42
42
|
_dirty = false;
|
|
43
|
-
this.SaveJsonToFile();
|
|
43
|
+
this.SaveJsonToFile(false);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
package/Runtime/AmaGDK.asmdef
CHANGED
package/Runtime/AmaGDK.cs
CHANGED
|
@@ -15,6 +15,7 @@ using Amanotes.Core.Internal;
|
|
|
15
15
|
using static Amanotes.Core.GDKDebug;
|
|
16
16
|
using static Amanotes.Core.Internal.Messsage;
|
|
17
17
|
using System.Threading.Tasks;
|
|
18
|
+
using Cysharp.Threading.Tasks;
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
#if UNITY_EDITOR
|
|
@@ -27,7 +28,7 @@ namespace Amanotes.Core
|
|
|
27
28
|
{
|
|
28
29
|
public partial class AmaGDK : MonoBehaviour
|
|
29
30
|
{
|
|
30
|
-
public const string VERSION = "v0.2.81-alpha.
|
|
31
|
+
public const string VERSION = "v0.2.81-alpha.17";
|
|
31
32
|
|
|
32
33
|
internal static Status _status = Status.None;
|
|
33
34
|
internal static ConfigAsset _config = null;
|
|
@@ -81,8 +82,8 @@ namespace Amanotes.Core
|
|
|
81
82
|
return _config;
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
|
|
86
|
+
async UniTask InitHook()
|
|
86
87
|
{
|
|
87
88
|
// dispatcher.Dispatch(Event.GDK_HOOK_START);
|
|
88
89
|
if (_onHookStart!= null) GDKUtils.SafeInvokeAndClear(ref _onHookStart);
|
|
@@ -91,24 +92,23 @@ namespace Amanotes.Core
|
|
|
91
92
|
{
|
|
92
93
|
Log($"[Hook] No hook registered!");
|
|
93
94
|
if (_onHookEnd!= null) GDKUtils.SafeInvokeAndClear(ref _onHookEnd);
|
|
94
|
-
|
|
95
|
+
return;
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
+
|
|
97
98
|
//TODO: Sort Hook by orderId
|
|
98
99
|
var hookCompleted = false;
|
|
99
|
-
|
|
100
|
+
|
|
100
101
|
float stTime = Time.realtimeSinceStartup;
|
|
101
102
|
Hook.TriggerHooks(() =>
|
|
102
103
|
{
|
|
103
104
|
hookCompleted = true;
|
|
104
105
|
});
|
|
105
|
-
|
|
106
|
+
await UniTask.WaitUntil(() => hookCompleted);
|
|
106
107
|
float elapsed = Time.realtimeSinceStartup - stTime;
|
|
107
108
|
Log($"[Hook] {nHooks} hooks complete after {elapsed} secs");
|
|
108
109
|
if (_onHookEnd!= null) GDKUtils.SafeInvokeAndClear(ref _onHookEnd);
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
-
IEnumerator WaitForManualInit()
|
|
111
|
+
async UniTask WaitForManualInit()
|
|
112
112
|
{
|
|
113
113
|
var counter = 0;
|
|
114
114
|
const int INIT_TOLERANCE = 10 * 60;
|
|
@@ -117,7 +117,7 @@ namespace Amanotes.Core
|
|
|
117
117
|
while (!_allowInit)
|
|
118
118
|
{
|
|
119
119
|
counter++;
|
|
120
|
-
|
|
120
|
+
await UniTask.Yield();
|
|
121
121
|
|
|
122
122
|
if (counter > INIT_TOLERANCE && counter % INIT_WARN_CYCLE == 1)
|
|
123
123
|
{
|
|
@@ -126,17 +126,20 @@ namespace Amanotes.Core
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
async UniTask InitModules()
|
|
130
130
|
{
|
|
131
131
|
Profiler.BeginSample("AmaGDK.InitModules()");
|
|
132
132
|
{
|
|
133
133
|
User.InitModule();
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
134
|
+
if (Config.enableAudioModule)
|
|
135
|
+
{
|
|
136
|
+
Audio.InitModule();
|
|
137
|
+
}
|
|
138
|
+
await Consent.InitModule();
|
|
139
|
+
await Analytics.InitModule();
|
|
140
|
+
await Ads.InitModule();
|
|
141
|
+
await IAP.InitModule();
|
|
142
|
+
await RemoteConfig.InitModule();
|
|
140
143
|
}
|
|
141
144
|
Profiler.EndSample();
|
|
142
145
|
}
|
|
@@ -154,13 +157,13 @@ namespace Amanotes.Core
|
|
|
154
157
|
Profiler.EndSample();
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
|
|
160
|
+
async UniTask InitAdapters(StringBuilder sb)
|
|
158
161
|
{
|
|
159
162
|
// sort on priority
|
|
160
163
|
List<Adapter2> listAdapters = Adapter2.adapterMap
|
|
161
164
|
.Values.ToList();
|
|
162
165
|
listAdapters.Sort((a1, a2) => a1.initOrder.CompareTo(a2.initOrder));
|
|
163
|
-
|
|
166
|
+
|
|
164
167
|
foreach (Adapter2 adapter in listAdapters)
|
|
165
168
|
{
|
|
166
169
|
if (!adapter.enabled)
|
|
@@ -168,7 +171,7 @@ namespace Amanotes.Core
|
|
|
168
171
|
Log($"Adapter <{adapter.adapterId} is disabled!");
|
|
169
172
|
continue;
|
|
170
173
|
}
|
|
171
|
-
|
|
174
|
+
|
|
172
175
|
// Log($"Initiating {adapter.adapterId} --> initOrder: {adapter.initOrder} | {adapter.status}");
|
|
173
176
|
var startTime = Time.realtimeSinceStartup;
|
|
174
177
|
Profiler.BeginSample($"AmaGDK.adapter.InitSDK-{adapter.adapterId}");
|
|
@@ -178,9 +181,9 @@ namespace Amanotes.Core
|
|
|
178
181
|
if (adapter.status != Status.Ready)
|
|
179
182
|
{
|
|
180
183
|
var beginTime = Time.realtimeSinceStartup;
|
|
181
|
-
|
|
182
|
-
var endTime = Time.realtimeSinceStartup;
|
|
183
|
-
|
|
184
|
+
await GDKUtils.TimeoutTask(adapter.Timeout,() => adapter.status != Status.Initialize);
|
|
185
|
+
var endTime = Time.realtimeSinceStartup;
|
|
186
|
+
|
|
184
187
|
if (adapter.status == Status.Initialize)
|
|
185
188
|
{
|
|
186
189
|
LogWarning($"{adapter.adapterId} init time out: {adapter.Timeout:#0.00}");
|
|
@@ -189,65 +192,66 @@ namespace Amanotes.Core
|
|
|
189
192
|
Log($"{adapter.adapterId} init took: {(endTime-beginTime):#0.00} s");
|
|
190
193
|
}
|
|
191
194
|
}
|
|
192
|
-
|
|
195
|
+
|
|
193
196
|
GDKUtils.SafeInvoke(_onAdapterReady, adapter.adapterId);
|
|
194
197
|
sb.AppendLine($"[{(adapter.IsReady ? " OK " : "FAIL")}] {adapter.adapterId} (~ {Time.realtimeSinceStartup - startTime:#0.00}s)");
|
|
195
|
-
|
|
198
|
+
|
|
196
199
|
// Wait for postprocessing of each adapter
|
|
197
|
-
|
|
200
|
+
await UniTask.Yield();
|
|
198
201
|
}
|
|
199
202
|
}
|
|
200
|
-
|
|
201
|
-
|
|
203
|
+
|
|
204
|
+
public async UniTask InitRoutine()
|
|
202
205
|
{
|
|
203
206
|
_allowInit = _allowInit || autoInit;
|
|
204
|
-
|
|
207
|
+
|
|
205
208
|
if (Config == null)
|
|
206
209
|
{
|
|
207
210
|
throw new Exception("[AmaGDK] " + CONFIG_NOT_FOUND);
|
|
208
211
|
}
|
|
209
|
-
|
|
212
|
+
|
|
210
213
|
var startTime = Time.realtimeSinceStartup;
|
|
211
214
|
var sb = GDKPool.GetStringBuilder();
|
|
212
215
|
|
|
213
|
-
InitModules();
|
|
214
|
-
|
|
216
|
+
await InitModules();
|
|
217
|
+
await UniTask.SwitchToMainThread();
|
|
215
218
|
var moduleTime = Time.realtimeSinceStartup - startTime;
|
|
216
219
|
sb.Append($"- InitModules() took (~ {moduleTime:#0.00}s)\n");
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
+
|
|
221
|
+
await InitHook(); //Google CMP takes long at first time (~ 1.7s)
|
|
222
|
+
|
|
220
223
|
var hookTime = Time.realtimeSinceStartup - moduleTime - startTime;
|
|
221
224
|
sb.Append($"- InitHook() took (~ {hookTime:#0.00}s)\n\n");
|
|
222
|
-
|
|
225
|
+
|
|
223
226
|
_status = Status.Initialize;
|
|
224
227
|
GDKUtils.SafeInvokeAndClear(ref _onGDKInit);
|
|
225
|
-
|
|
226
|
-
if (!_allowInit)
|
|
227
|
-
|
|
228
|
-
|
|
228
|
+
|
|
229
|
+
if (!_allowInit)
|
|
230
|
+
await WaitForManualInit();
|
|
231
|
+
await InitAdapters(sb);
|
|
232
|
+
|
|
229
233
|
StartModules();
|
|
230
|
-
|
|
234
|
+
|
|
231
235
|
ConfigGeoLocation();
|
|
232
236
|
if (Config.enableServerTime)
|
|
233
237
|
{
|
|
234
238
|
ServerTime.UpdateTime();
|
|
235
239
|
}
|
|
236
|
-
|
|
240
|
+
|
|
237
241
|
ForceQuit.Init();
|
|
238
|
-
|
|
242
|
+
|
|
239
243
|
_status = Status.Ready;
|
|
240
244
|
GDKUtils.SafeInvokeAndClear(ref _onGDKReady);
|
|
241
245
|
|
|
242
246
|
float initDuration = Time.realtimeSinceStartup - startTime;
|
|
243
247
|
|
|
244
|
-
|
|
248
|
+
await LogEvent_GDKInitAsync(Mathf.RoundToInt(initDuration));
|
|
249
|
+
|
|
245
250
|
|
|
246
|
-
|
|
247
251
|
sb.Append($"\nMapping UserId: {User.UserId}\n");
|
|
248
252
|
ForceLog($"v{VERSION} | {READY} in {initDuration:#0.00}s\n\n{sb}");
|
|
249
253
|
GDKPool.Return(sb);
|
|
250
|
-
|
|
254
|
+
|
|
251
255
|
// also clear callbacks
|
|
252
256
|
_onAdapterReady = null;
|
|
253
257
|
}
|
|
@@ -272,7 +276,7 @@ namespace Amanotes.Core
|
|
|
272
276
|
}
|
|
273
277
|
}
|
|
274
278
|
|
|
275
|
-
public static async
|
|
279
|
+
public static async UniTask<Dictionary<string, object>> ParseThirdPartyVersionsAsync()
|
|
276
280
|
{
|
|
277
281
|
Dictionary<string, object> thirdPartyVersions = new Dictionary<string, object>();
|
|
278
282
|
string fileContent = await GDKFileUtils.LoadFromStreamingAssets("SDKVersion.txt");
|
|
@@ -325,7 +329,7 @@ namespace Amanotes.Core
|
|
|
325
329
|
}
|
|
326
330
|
}
|
|
327
331
|
|
|
328
|
-
private static async
|
|
332
|
+
private static async UniTask LogEvent_GDKInitAsync(int initDuration)
|
|
329
333
|
{
|
|
330
334
|
var BToMB = 1.0 / (1024 * 1024);
|
|
331
335
|
var reservedMemory = Math.Round(Profiler.GetTotalReservedMemoryLong() * BToMB, 2); // in MB
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
using System;
|
|
2
2
|
using Amanotes.Core.Internal;
|
|
3
|
+
using Cysharp.Threading.Tasks;
|
|
3
4
|
using UnityEngine;
|
|
4
5
|
using static Amanotes.Core.GDKDebug;
|
|
5
6
|
|
|
@@ -76,7 +77,7 @@ namespace Amanotes.Core
|
|
|
76
77
|
ConsentHook.ATTRequest(isAllowed =>
|
|
77
78
|
{
|
|
78
79
|
data.att = isAllowed ? Status.Allowed : Status.NotAllowed;
|
|
79
|
-
data.SaveJsonToFile();
|
|
80
|
+
data.SaveJsonToFile(false);
|
|
80
81
|
onComplete?.Invoke(allowedATT);
|
|
81
82
|
});
|
|
82
83
|
}
|
|
@@ -119,7 +120,7 @@ namespace Amanotes.Core
|
|
|
119
120
|
{
|
|
120
121
|
data.canShowAds = canShowAd;
|
|
121
122
|
data.consentAlreadyShown = true;
|
|
122
|
-
data.SaveJsonToFile();
|
|
123
|
+
data.SaveJsonToFile(false);
|
|
123
124
|
onComplete?.Invoke(canShowAd);
|
|
124
125
|
}, onError);
|
|
125
126
|
}
|
|
@@ -170,8 +171,7 @@ namespace Amanotes.Core
|
|
|
170
171
|
|
|
171
172
|
public static partial class Consent //Internal
|
|
172
173
|
{
|
|
173
|
-
private static
|
|
174
|
-
private static ConsentData data => _data.Value;
|
|
174
|
+
private static ConsentData data;
|
|
175
175
|
private static Action _onConsentComplete;
|
|
176
176
|
|
|
177
177
|
internal static bool checkedATT => data.att >= Status.Allowed;
|
|
@@ -185,13 +185,14 @@ namespace Amanotes.Core
|
|
|
185
185
|
NotAllowed
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
internal static
|
|
188
|
+
internal static async UniTask InitModule()
|
|
189
189
|
{
|
|
190
|
+
await UniTask.SwitchToThreadPool();
|
|
190
191
|
if (_config.autoGetConsent)
|
|
191
192
|
{
|
|
192
193
|
RequestAllConsents(null);
|
|
193
194
|
}
|
|
194
|
-
|
|
195
|
+
data = new ConsentData().LoadJsonFromFile();
|
|
195
196
|
}
|
|
196
197
|
}
|
|
197
198
|
}
|
package/Runtime/Core/GDKDebug.cs
CHANGED
|
@@ -11,7 +11,8 @@ namespace Amanotes.Core
|
|
|
11
11
|
Warning,
|
|
12
12
|
Verbose
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
#if GDK_REMOVE_STACKTRACE
|
|
15
16
|
internal readonly struct NoStackTrace : IDisposable
|
|
16
17
|
{
|
|
17
18
|
internal readonly LogType logType;
|
|
@@ -41,10 +42,13 @@ namespace Amanotes.Core
|
|
|
41
42
|
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
#endif
|
|
44
46
|
|
|
45
47
|
public class GDKDebug
|
|
46
48
|
{
|
|
49
|
+
#if GDK_REMOVE_STACKTRACE
|
|
47
50
|
internal static readonly IDisposable NoStackTraceNull = new NoStackTraceNull();
|
|
51
|
+
#endif
|
|
48
52
|
|
|
49
53
|
public static Action<string> logNonfatalErrorHook = null;
|
|
50
54
|
private static readonly HashSet<string> nonFatalDict = new HashSet<string>();
|
|
@@ -59,7 +63,9 @@ namespace Amanotes.Core
|
|
|
59
63
|
if (!logWarningDict.Add(key)) return;
|
|
60
64
|
}
|
|
61
65
|
|
|
66
|
+
#if GDK_REMOVE_STACKTRACE
|
|
62
67
|
using (GDKUtils.isOnMainThread ? NoStackTrace.Warning: NoStackTraceNull)
|
|
68
|
+
#endif
|
|
63
69
|
{
|
|
64
70
|
Debug.LogWarning($"AmaGDK {message}");
|
|
65
71
|
}
|
|
@@ -67,7 +73,9 @@ namespace Amanotes.Core
|
|
|
67
73
|
public static void LogWarning(string message)
|
|
68
74
|
{
|
|
69
75
|
if (AmaGDK.logLevel < LogLevel.Warning) return;
|
|
76
|
+
#if GDK_REMOVE_STACKTRACE
|
|
70
77
|
using (GDKUtils.isOnMainThread ? NoStackTrace.Warning: NoStackTraceNull)
|
|
78
|
+
#endif
|
|
71
79
|
{
|
|
72
80
|
Debug.LogWarning($"AmaGDK {message}");
|
|
73
81
|
}
|
|
@@ -75,7 +83,9 @@ namespace Amanotes.Core
|
|
|
75
83
|
public static void LogError(string message)
|
|
76
84
|
{
|
|
77
85
|
if (AmaGDK.logLevel < LogLevel.Error) return;
|
|
86
|
+
#if GDK_REMOVE_STACKTRACE
|
|
78
87
|
using (GDKUtils.isOnMainThread ? NoStackTrace.Error: NoStackTraceNull)
|
|
88
|
+
#endif
|
|
79
89
|
{
|
|
80
90
|
Debug.LogError($"AmaGDK {message}");
|
|
81
91
|
}
|
|
@@ -100,7 +110,9 @@ namespace Amanotes.Core
|
|
|
100
110
|
public static void Log(string message)
|
|
101
111
|
{
|
|
102
112
|
if (AmaGDK.logLevel < LogLevel.Verbose) return;
|
|
113
|
+
#if GDK_REMOVE_STACKTRACE
|
|
103
114
|
using (GDKUtils.isOnMainThread ? NoStackTrace.Log: NoStackTraceNull)
|
|
115
|
+
#endif
|
|
104
116
|
{
|
|
105
117
|
Debug.Log($"AmaGDK {message}");
|
|
106
118
|
}
|
|
@@ -108,7 +120,9 @@ namespace Amanotes.Core
|
|
|
108
120
|
|
|
109
121
|
public static void ForceLog(string message)
|
|
110
122
|
{
|
|
123
|
+
#if GDK_REMOVE_STACKTRACE
|
|
111
124
|
using (GDKUtils.isOnMainThread ? NoStackTrace.Log: NoStackTraceNull)
|
|
125
|
+
#endif
|
|
112
126
|
{
|
|
113
127
|
Debug.Log($"AmaGDK {message}");
|
|
114
128
|
}
|
|
@@ -200,7 +200,7 @@ namespace Amanotes.Core.Internal
|
|
|
200
200
|
return GDKFileUtils.LoadJsonFromFile(instance);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
internal static void SaveJsonToFile<T>(this T instance, bool immediately
|
|
203
|
+
internal static void SaveJsonToFile<T>(this T instance, bool immediately) where T: IJsonFile
|
|
204
204
|
{
|
|
205
205
|
GDKFileUtils.SaveJsonToFile(instance, immediately);
|
|
206
206
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
// #define GDK_DEBUG_FILE_IO
|
|
2
|
+
|
|
1
3
|
using System;
|
|
4
|
+
using System.Collections.Concurrent;
|
|
2
5
|
using System.Collections.Generic;
|
|
6
|
+
using System.Diagnostics;
|
|
3
7
|
using System.IO;
|
|
8
|
+
using System.Threading;
|
|
4
9
|
using System.Threading.Tasks;
|
|
5
10
|
using UnityEngine;
|
|
6
11
|
using UnityEngine.Networking;
|
|
@@ -11,64 +16,145 @@ namespace Amanotes.Core.Internal
|
|
|
11
16
|
public static class GDKFileUtils
|
|
12
17
|
{
|
|
13
18
|
private static string _basePath;
|
|
19
|
+
private static readonly ConcurrentDictionary<string, string> _pendingWrites =
|
|
20
|
+
new ConcurrentDictionary<string, string>();
|
|
21
|
+
private static readonly List<KeyValuePair<string, string>> _itemsToWrite =
|
|
22
|
+
new List<KeyValuePair<string, string>>(8);
|
|
23
|
+
|
|
24
|
+
private static readonly object _fileLock = new object();
|
|
25
|
+
private static int _isProcessing = 0;
|
|
26
|
+
|
|
14
27
|
public static string basePath
|
|
15
28
|
{
|
|
16
29
|
get
|
|
17
30
|
{
|
|
18
31
|
if (!string.IsNullOrEmpty(_basePath)) return _basePath;
|
|
32
|
+
|
|
19
33
|
_basePath = Application.isEditor
|
|
20
34
|
? Path.Combine(Directory.GetCurrentDirectory(), "Library", "AmaGDK")
|
|
21
35
|
: Path.Combine(Application.persistentDataPath, "AmaGDK");
|
|
22
36
|
|
|
23
|
-
|
|
37
|
+
try
|
|
38
|
+
{
|
|
39
|
+
if (!Directory.Exists(_basePath))
|
|
40
|
+
{
|
|
41
|
+
Directory.CreateDirectory(_basePath);
|
|
42
|
+
}
|
|
43
|
+
} catch (Exception ex)
|
|
44
|
+
{
|
|
45
|
+
LogError($"[GDKFileUtils] Failed to create directory: {ex.Message}");
|
|
46
|
+
_basePath = Application.persistentDataPath;
|
|
47
|
+
}
|
|
48
|
+
|
|
24
49
|
return _basePath;
|
|
25
50
|
}
|
|
26
51
|
}
|
|
27
|
-
|
|
52
|
+
|
|
28
53
|
internal static string GetPath(string fileName)
|
|
29
54
|
{
|
|
30
|
-
|
|
55
|
+
if (string.IsNullOrEmpty(fileName)) return null;
|
|
56
|
+
return Path.Combine(basePath, Path.GetFileName(fileName));
|
|
31
57
|
}
|
|
32
58
|
|
|
33
59
|
internal static bool Exist(string fileName)
|
|
34
60
|
{
|
|
35
|
-
|
|
61
|
+
if (string.IsNullOrEmpty(fileName)) return false;
|
|
62
|
+
|
|
63
|
+
string path = GetPath(fileName);
|
|
64
|
+
if (string.IsNullOrEmpty(path)) return false;
|
|
65
|
+
|
|
66
|
+
lock (_fileLock)
|
|
67
|
+
{
|
|
68
|
+
return File.Exists(path);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
internal static int writePendingCount => _pendingWrites.Count;
|
|
73
|
+
internal static bool HasAnyWritePending => _pendingWrites.Count > 0;
|
|
74
|
+
internal static bool IsWritePending(string fileName)
|
|
75
|
+
{
|
|
76
|
+
return !string.IsNullOrEmpty(fileName) && _pendingWrites.ContainsKey(fileName);
|
|
36
77
|
}
|
|
37
|
-
|
|
38
|
-
public static void Save(string fileName, string content, bool immediately
|
|
78
|
+
|
|
79
|
+
public static void Save(string fileName, string content, bool immediately)
|
|
39
80
|
{
|
|
40
|
-
if (string.
|
|
81
|
+
if (string.IsNullOrEmpty(fileName)) return;
|
|
82
|
+
|
|
83
|
+
if (immediately)
|
|
41
84
|
{
|
|
42
|
-
|
|
85
|
+
_pendingWrites.TryRemove(fileName, out _);
|
|
86
|
+
WriteFileDirectly(fileName, content);
|
|
43
87
|
return;
|
|
44
88
|
}
|
|
45
89
|
|
|
46
|
-
|
|
90
|
+
// Just replace any existing content
|
|
91
|
+
_pendingWrites[fileName] = content;
|
|
92
|
+
|
|
93
|
+
// Use atomic CompareExchange to ensure only one Task runs at a time
|
|
94
|
+
CheckSpawnThread();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private static void CheckSpawnThread()
|
|
98
|
+
{
|
|
99
|
+
if (Interlocked.CompareExchange(ref _isProcessing, 1, 0) == 0)
|
|
47
100
|
{
|
|
48
|
-
|
|
101
|
+
Task.Factory.StartNew(ProcessWriteQueue, TaskCreationOptions.None);
|
|
49
102
|
}
|
|
50
|
-
|
|
51
|
-
ThreadWrite(fileName, content, immediately);
|
|
52
103
|
}
|
|
53
104
|
|
|
54
|
-
private static void
|
|
105
|
+
private static void ProcessWriteQueue()
|
|
55
106
|
{
|
|
56
|
-
|
|
57
|
-
if (!immediately && GDKUtils.isOnMainThread)
|
|
107
|
+
try
|
|
58
108
|
{
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
109
|
+
// var w = Stopwatch.StartNew();
|
|
110
|
+
while (!_pendingWrites.IsEmpty)
|
|
111
|
+
{
|
|
112
|
+
// Blocking delay so batching actually occurs
|
|
113
|
+
// In this case, it's actually better than await Task.Delay(500), why?
|
|
114
|
+
Thread.Sleep(500);
|
|
115
|
+
|
|
116
|
+
_itemsToWrite.Clear();
|
|
117
|
+
_itemsToWrite.AddRange(_pendingWrites);
|
|
118
|
+
_pendingWrites.Clear();
|
|
119
|
+
|
|
120
|
+
lock (_fileLock)
|
|
121
|
+
{
|
|
122
|
+
foreach (var kvp in _itemsToWrite)
|
|
123
|
+
{
|
|
124
|
+
WriteFileDirectly(kvp.Key, kvp.Value);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// w.Stop();
|
|
130
|
+
// LogWarning($"Process time: {w.ElapsedTicks} ticks | {w.ElapsedMilliseconds} milliseconds");
|
|
131
|
+
}
|
|
132
|
+
catch (Exception e)
|
|
133
|
+
{
|
|
134
|
+
LogError($"[GDKFileUtils] Write queue error: {e.Message}");
|
|
135
|
+
} finally
|
|
136
|
+
{
|
|
137
|
+
Interlocked.Exchange(ref _isProcessing, 0);
|
|
138
|
+
if (!_pendingWrites.IsEmpty) CheckSpawnThread(); // until next time!
|
|
62
139
|
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Write directly to file without temp files
|
|
143
|
+
private static void WriteFileDirectly(string fileName, string content)
|
|
144
|
+
{
|
|
145
|
+
if (string.IsNullOrEmpty(fileName)) return;
|
|
63
146
|
|
|
64
147
|
string filePath = GetPath(fileName);
|
|
65
|
-
|
|
148
|
+
if (string.IsNullOrEmpty(filePath)) return;
|
|
149
|
+
|
|
150
|
+
// Lock only for the duration of actual I/O
|
|
151
|
+
lock (_fileLock)
|
|
66
152
|
{
|
|
67
153
|
File.WriteAllText(filePath, content);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
154
|
+
|
|
155
|
+
#if GDK_DEBUG_FILE_IO
|
|
156
|
+
Log($"WriteFileDirectly threadId={Thread.CurrentThread.ManagedThreadId}: {fileName} -> {content}");
|
|
157
|
+
#endif
|
|
72
158
|
}
|
|
73
159
|
}
|
|
74
160
|
|
|
@@ -76,23 +162,28 @@ namespace Amanotes.Core.Internal
|
|
|
76
162
|
{
|
|
77
163
|
if (string.IsNullOrWhiteSpace(fileName))
|
|
78
164
|
{
|
|
79
|
-
LogWarningOnce("File name must be
|
|
165
|
+
LogWarningOnce("File name must not be null or empty");
|
|
80
166
|
return;
|
|
81
167
|
}
|
|
82
|
-
|
|
168
|
+
|
|
169
|
+
// Check if `contents` is null or empty
|
|
83
170
|
if (contents == null || !contents.GetEnumerator().MoveNext())
|
|
84
171
|
{
|
|
85
172
|
LogWarningOnce($"Content for {fileName} is empty");
|
|
86
173
|
}
|
|
87
174
|
|
|
88
175
|
string path = GetPath(fileName);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
catch (Exception ex)
|
|
176
|
+
|
|
177
|
+
// Concurrency-safe write
|
|
178
|
+
lock (_fileLock)
|
|
94
179
|
{
|
|
95
|
-
|
|
180
|
+
try
|
|
181
|
+
{
|
|
182
|
+
File.AppendAllLines(path, contents);
|
|
183
|
+
} catch (Exception ex)
|
|
184
|
+
{
|
|
185
|
+
LogWarningOnce(path + "\n" + ex);
|
|
186
|
+
}
|
|
96
187
|
}
|
|
97
188
|
}
|
|
98
189
|
|
|
@@ -100,147 +191,192 @@ namespace Amanotes.Core.Internal
|
|
|
100
191
|
{
|
|
101
192
|
if (string.IsNullOrWhiteSpace(fileName))
|
|
102
193
|
{
|
|
103
|
-
LogWarningOnce("File name must be
|
|
194
|
+
LogWarningOnce("File name must not be null or empty");
|
|
104
195
|
return;
|
|
105
196
|
}
|
|
106
197
|
|
|
198
|
+
// Check if `content` is null or empty
|
|
107
199
|
if (string.IsNullOrWhiteSpace(content))
|
|
108
200
|
{
|
|
109
201
|
LogWarningOnce($"Content for {fileName} is empty");
|
|
110
202
|
}
|
|
111
203
|
|
|
112
204
|
string path = GetPath(fileName);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
catch (Exception ex)
|
|
205
|
+
|
|
206
|
+
// Concurrency-safe write
|
|
207
|
+
lock (_fileLock)
|
|
118
208
|
{
|
|
119
|
-
|
|
209
|
+
try
|
|
210
|
+
{
|
|
211
|
+
File.AppendAllText(path, content);
|
|
212
|
+
} catch (Exception ex)
|
|
213
|
+
{
|
|
214
|
+
LogWarningOnce(path + "\n" + ex);
|
|
215
|
+
}
|
|
120
216
|
}
|
|
121
217
|
}
|
|
122
218
|
|
|
123
219
|
public static string Load(string fileName)
|
|
124
220
|
{
|
|
125
|
-
|
|
221
|
+
if (string.IsNullOrEmpty(fileName)) return string.Empty;
|
|
126
222
|
|
|
127
|
-
|
|
223
|
+
// If there's a pending in-memory write, return that content first
|
|
224
|
+
if (_pendingWrites.TryGetValue(fileName, out var inMemoryContent))
|
|
128
225
|
{
|
|
129
|
-
|
|
130
|
-
return content;
|
|
226
|
+
return inMemoryContent;
|
|
131
227
|
}
|
|
132
228
|
|
|
133
229
|
string path = GetPath(fileName);
|
|
134
|
-
if (
|
|
230
|
+
if (string.IsNullOrEmpty(path)) return string.Empty;
|
|
135
231
|
|
|
136
|
-
|
|
137
|
-
{
|
|
138
|
-
content = File.ReadAllText(path);
|
|
139
|
-
}
|
|
140
|
-
catch (Exception ex)
|
|
232
|
+
lock (_fileLock)
|
|
141
233
|
{
|
|
142
|
-
|
|
234
|
+
try
|
|
235
|
+
{
|
|
236
|
+
return !File.Exists(path) ? string.Empty : File.ReadAllText(path);
|
|
237
|
+
} catch (Exception ex)
|
|
238
|
+
{
|
|
239
|
+
LogError($"[GDKFileUtils] Failed to read {fileName}: {ex.Message}");
|
|
240
|
+
return string.Empty;
|
|
241
|
+
}
|
|
143
242
|
}
|
|
144
|
-
|
|
145
|
-
return content;
|
|
146
243
|
}
|
|
147
244
|
|
|
148
245
|
public static async Task<string> LoadFromStreamingAssets(string fileName)
|
|
149
246
|
{
|
|
247
|
+
if (string.IsNullOrEmpty(fileName)) return null;
|
|
150
248
|
string filePath = Path.Combine(Application.streamingAssetsPath, fileName);
|
|
151
249
|
|
|
152
|
-
// Android
|
|
153
250
|
if (Application.platform == RuntimePlatform.Android)
|
|
154
251
|
{
|
|
155
|
-
using (
|
|
252
|
+
using (var request = UnityWebRequest.Get(filePath))
|
|
156
253
|
{
|
|
157
|
-
|
|
158
|
-
while (!operation.isDone)
|
|
254
|
+
try
|
|
159
255
|
{
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
256
|
+
var operation = request.SendWebRequest();
|
|
257
|
+
while (!operation.isDone)
|
|
258
|
+
{
|
|
259
|
+
await Task.Yield();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return request.result != UnityWebRequest.Result.Success
|
|
263
|
+
? null
|
|
264
|
+
: request.downloadHandler.text;
|
|
265
|
+
} catch (Exception ex)
|
|
163
266
|
{
|
|
164
|
-
|
|
267
|
+
LogError($"[GDKFileUtils] StreamingAssets load error: {ex.Message}");
|
|
165
268
|
return null;
|
|
166
269
|
}
|
|
167
|
-
return request.downloadHandler.text;
|
|
168
270
|
}
|
|
169
271
|
}
|
|
170
272
|
|
|
171
|
-
|
|
172
|
-
try
|
|
173
|
-
{
|
|
174
|
-
return File.ReadAllText(filePath);
|
|
175
|
-
}
|
|
176
|
-
catch (Exception e)
|
|
273
|
+
lock (_fileLock)
|
|
177
274
|
{
|
|
178
|
-
|
|
275
|
+
try
|
|
276
|
+
{
|
|
277
|
+
return File.ReadAllText(filePath);
|
|
278
|
+
} catch (Exception ex)
|
|
279
|
+
{
|
|
280
|
+
LogError($"[GDKFileUtils] StreamingAssets load error: {ex.Message}");
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
179
283
|
}
|
|
180
|
-
return null;
|
|
181
284
|
}
|
|
182
285
|
|
|
183
|
-
|
|
184
286
|
internal static void Delete(string fileName)
|
|
185
287
|
{
|
|
288
|
+
if (string.IsNullOrEmpty(fileName)) return;
|
|
289
|
+
|
|
290
|
+
_pendingWrites.TryRemove(fileName, out _);
|
|
291
|
+
|
|
186
292
|
string path = GetPath(fileName);
|
|
187
|
-
if (
|
|
293
|
+
if (string.IsNullOrEmpty(path)) return;
|
|
188
294
|
|
|
189
|
-
|
|
295
|
+
lock (_fileLock)
|
|
190
296
|
{
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
297
|
+
try
|
|
298
|
+
{
|
|
299
|
+
if (File.Exists(path))
|
|
300
|
+
{
|
|
301
|
+
File.Delete(path);
|
|
302
|
+
}
|
|
303
|
+
} catch (Exception ex)
|
|
304
|
+
{
|
|
305
|
+
LogError($"[GDKFileUtils] Delete error: {ex.Message}");
|
|
306
|
+
}
|
|
196
307
|
}
|
|
197
308
|
}
|
|
198
|
-
|
|
309
|
+
|
|
199
310
|
public static void ClearCacheData()
|
|
200
311
|
{
|
|
201
|
-
|
|
202
|
-
|
|
312
|
+
_pendingWrites.Clear();
|
|
313
|
+
|
|
314
|
+
if (!Directory.Exists(basePath)) return;
|
|
203
315
|
|
|
204
|
-
|
|
316
|
+
lock (_fileLock)
|
|
205
317
|
{
|
|
206
|
-
|
|
207
|
-
|
|
318
|
+
foreach (string file in Directory.GetFiles(basePath))
|
|
319
|
+
{
|
|
320
|
+
try
|
|
321
|
+
{
|
|
322
|
+
File.Delete(file);
|
|
323
|
+
} catch (Exception ex)
|
|
324
|
+
{
|
|
325
|
+
LogWarning($"[GDKFileUtils] Failed to delete {file}: {ex.Message}");
|
|
326
|
+
}
|
|
327
|
+
}
|
|
208
328
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Synchronously flush everything
|
|
332
|
+
public static void Shutdown()
|
|
333
|
+
{
|
|
334
|
+
// Write out all pending items directly
|
|
335
|
+
foreach (var kvp in _pendingWrites)
|
|
212
336
|
{
|
|
213
|
-
|
|
214
|
-
|
|
337
|
+
try
|
|
338
|
+
{
|
|
339
|
+
WriteFileDirectly(kvp.Key, kvp.Value);
|
|
340
|
+
} catch (Exception ex)
|
|
341
|
+
{
|
|
342
|
+
LogError($"[GDKFileUtils] Shutdown write error: {ex.Message}");
|
|
343
|
+
}
|
|
215
344
|
}
|
|
216
|
-
|
|
345
|
+
|
|
346
|
+
_pendingWrites.Clear();
|
|
217
347
|
}
|
|
218
|
-
|
|
219
|
-
public static T LoadJsonFromFile<T>(T instance) where T: new()
|
|
348
|
+
|
|
349
|
+
public static T LoadJsonFromFile<T>(T instance) where T : new()
|
|
220
350
|
{
|
|
221
351
|
instance ??= new T();
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
string json = Load(fileName);
|
|
225
|
-
if (!string.IsNullOrEmpty(json))
|
|
352
|
+
|
|
353
|
+
try
|
|
226
354
|
{
|
|
227
|
-
|
|
355
|
+
string json = Load(instance.GetType().Name);
|
|
356
|
+
if (!string.IsNullOrEmpty(json))
|
|
228
357
|
{
|
|
229
358
|
JsonUtility.FromJsonOverwrite(json, instance);
|
|
230
|
-
} catch (Exception e)
|
|
231
|
-
{
|
|
232
|
-
LogWarning("LoadJsonFromFile error: " + fileName + "\n" + e);
|
|
233
359
|
}
|
|
360
|
+
} catch (Exception ex)
|
|
361
|
+
{
|
|
362
|
+
LogError($"[GDKFileUtils] JSON load error: {ex.Message}");
|
|
234
363
|
}
|
|
235
|
-
|
|
364
|
+
|
|
236
365
|
return instance;
|
|
237
366
|
}
|
|
238
|
-
|
|
239
|
-
public static void SaveJsonToFile<T>(T instance, bool immediately
|
|
367
|
+
|
|
368
|
+
public static void SaveJsonToFile<T>(T instance, bool immediately)
|
|
240
369
|
{
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
370
|
+
if (instance == null) return;
|
|
371
|
+
|
|
372
|
+
try
|
|
373
|
+
{
|
|
374
|
+
string json = JsonUtility.ToJson(instance);
|
|
375
|
+
Save(instance.GetType().Name, json, immediately);
|
|
376
|
+
} catch (Exception ex)
|
|
377
|
+
{
|
|
378
|
+
LogError($"[GDKFileUtils] JSON save error: {ex.Message}");
|
|
379
|
+
}
|
|
244
380
|
}
|
|
245
381
|
}
|
|
246
382
|
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
"name": "com.amanotes.gdk",
|
|
3
|
+
"version": "0.2.81-alpha.17",
|
|
4
|
+
"displayName": "AmaGDK",
|
|
5
|
+
"description": "Amanotes Game Development Kit",
|
|
6
|
+
"unity": "2019.4",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"Amanotes",
|
|
9
|
+
"Amanotes GDK",
|
|
10
|
+
"vh-name:AmaGDK"
|
|
11
|
+
],
|
|
12
|
+
"author": {
|
|
13
|
+
"name": "Amanotes",
|
|
14
|
+
"email": "tech.support@amanotes.com",
|
|
15
|
+
"url": "https://amanotes.com"
|
|
16
|
+
},
|
|
17
|
+
"changelogUrl": "https://amagdk.notion.site/Change-Log-6dfd4b67d64f496bbd9eb04ccb4ef95a",
|
|
18
|
+
"documentationUrl": "https://amagdk.notion.site/amagdk/Ama-GDK-a73596617ab247b6a43c8f12a1581415",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"com.cysharp.unitask": "2.5.10"
|
|
22
|
+
},
|
|
23
|
+
"scopedRegistries": [
|
|
24
|
+
{
|
|
25
|
+
"name": "OpenUPM",
|
|
26
|
+
"url": "https://package.openupm.com",
|
|
27
|
+
"scopes": [
|
|
28
|
+
"com.cysharp"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
20
32
|
}
|