com.taptap.sdk.cloudsave 4.10.1-beta.1 → 4.10.2

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 (64) hide show
  1. package/Mobile/Editor/NativeDependencies.xml +14 -14
  2. package/Mobile/Editor/NativeDependencies.xml.meta +2 -2
  3. package/Mobile/Editor/TapCloudSaveMobileProcessBuild.cs +20 -20
  4. package/Mobile/Editor/TapCloudSaveMobileProcessBuild.cs.meta +11 -11
  5. package/Mobile/Editor/TapSDK.CloudSave.Mobile.Editor.asmdef +16 -16
  6. package/Mobile/Editor/TapSDK.CloudSave.Mobile.Editor.asmdef.meta +7 -7
  7. package/Mobile/Editor.meta +8 -8
  8. package/Mobile/Runtime/TapCloudSaveBridge.cs +589 -589
  9. package/Mobile/Runtime/TapCloudSaveBridge.cs.meta +11 -11
  10. package/Mobile/Runtime/TapSDK.CloudSave.Mobile.Runtime.asmdef +19 -19
  11. package/Mobile/Runtime/TapSDK.CloudSave.Mobile.Runtime.asmdef.meta +7 -7
  12. package/Mobile/Runtime.meta +8 -8
  13. package/Mobile.meta +8 -8
  14. package/Runtime/Internal/ITapCloudSaveBridge.cs +24 -24
  15. package/Runtime/Internal/ITapCloudSaveBridge.cs.meta +11 -11
  16. package/Runtime/Internal/TapCloudSaveInitTask.cs +19 -19
  17. package/Runtime/Internal/TapCloudSaveInitTask.cs.meta +11 -11
  18. package/Runtime/Internal/TapTapCloudSaveInternal.cs +51 -51
  19. package/Runtime/Internal/TapTapCloudSaveInternal.cs.meta +11 -11
  20. package/Runtime/Internal.meta +8 -8
  21. package/Runtime/Public/ArchiveData.cs +33 -33
  22. package/Runtime/Public/ArchiveData.cs.meta +2 -2
  23. package/Runtime/Public/ITapCloudSaveCallback.cs +8 -8
  24. package/Runtime/Public/ITapCloudSaveCallback.cs.meta +2 -2
  25. package/Runtime/Public/ITapCloudSaveRequestCallback.cs +14 -14
  26. package/Runtime/Public/ITapCloudSaveRequestCallback.cs.meta +2 -2
  27. package/Runtime/Public/TapCloudSaveRequestCallbackAdapter.cs +34 -34
  28. package/Runtime/Public/TapCloudSaveRequestCallbackAdapter.cs.meta +2 -2
  29. package/Runtime/Public/TapTapCloudSave.cs +39 -39
  30. package/Runtime/Public/TapTapCloudSave.cs.meta +11 -11
  31. package/Runtime/Public.meta +8 -8
  32. package/Runtime/TapSDK.CloudSave.Runtime.asmdef +14 -14
  33. package/Runtime/TapSDK.CloudSave.Runtime.asmdef.meta +7 -7
  34. package/Runtime.meta +8 -8
  35. package/Standalone/Editor/TapCloudSaveStandaloneProcessBuild.cs +26 -26
  36. package/Standalone/Editor/TapCloudSaveStandaloneProcessBuild.cs.meta +11 -11
  37. package/Standalone/Editor/TapSDK.CloudSave.Standalone.Editor.asmdef +16 -16
  38. package/Standalone/Editor/TapSDK.CloudSave.Standalone.Editor.asmdef.meta +7 -7
  39. package/Standalone/Editor.meta +8 -8
  40. package/Standalone/Plugins/x86_64/cloudsave_sdk.dll +0 -0
  41. package/Standalone/Plugins/x86_64/cloudsave_sdk.dll.meta +80 -80
  42. package/Standalone/Plugins/x86_64.meta +8 -8
  43. package/Standalone/Plugins.meta +8 -8
  44. package/Standalone/Runtime/Internal/TapCloudSaveArchiveListResponse.cs +11 -11
  45. package/Standalone/Runtime/Internal/TapCloudSaveArchiveListResponse.cs.meta +11 -11
  46. package/Standalone/Runtime/Internal/TapCloudSaveBaseResponse.cs +29 -29
  47. package/Standalone/Runtime/Internal/TapCloudSaveBaseResponse.cs.meta +11 -11
  48. package/Standalone/Runtime/Internal/TapCloudSaveTracker.cs +101 -101
  49. package/Standalone/Runtime/Internal/TapCloudSaveTracker.cs.meta +11 -11
  50. package/Standalone/Runtime/Internal/TapCloudSaveWrapper.cs +583 -561
  51. package/Standalone/Runtime/Internal/TapCloudSaveWrapper.cs.meta +11 -11
  52. package/Standalone/Runtime/Internal.meta +8 -8
  53. package/Standalone/Runtime/TapCloudSaveResultCode.cs +9 -9
  54. package/Standalone/Runtime/TapCloudSaveResultCode.cs.meta +11 -11
  55. package/Standalone/Runtime/TapCloudSaveStandalone.cs +712 -712
  56. package/Standalone/Runtime/TapCloudSaveStandalone.cs.meta +11 -11
  57. package/Standalone/Runtime.meta +8 -8
  58. package/Standalone/TapSDK.CloudSave.Standalone.Runtime.asmdef +21 -21
  59. package/Standalone/TapSDK.CloudSave.Standalone.Runtime.asmdef.meta +7 -7
  60. package/Standalone.meta +8 -8
  61. package/link.xml +3 -3
  62. package/link.xml.meta +7 -7
  63. package/package.json +11 -11
  64. package/package.json.meta +7 -7
@@ -1,712 +1,712 @@
1
- using System;
2
- using System.Collections.Generic;
3
- using System.IO;
4
- using System.Text;
5
- using System.Threading.Tasks;
6
- using Newtonsoft.Json;
7
- using TapSDK.CloudSave.Internal;
8
- using TapSDK.Core;
9
- using TapSDK.Core.Internal.Log;
10
- using TapSDK.Core.Internal.Utils;
11
- using TapSDK.Core.Standalone;
12
- using TapSDK.Core.Standalone.Internal;
13
- using TapSDK.Core.Standalone.Internal.Http;
14
- using TapSDK.Login;
15
- using UnityEngine;
16
-
17
- namespace TapSDK.CloudSave.Standalone
18
- {
19
- public class TapCloudSaveStandalone : ITapCloudSaveBridge
20
- {
21
- private List<ITapCloudSaveCallback> currentSaveCallback = null;
22
- private static readonly bool isRND = false;
23
- private bool _hasInitNative = false;
24
- private object _lockObj = new object();
25
-
26
- private TapLog cloudSaveLog;
27
-
28
- public void Init(TapTapSdkOptions options)
29
- {
30
- Log("TapCloudSave start init");
31
- string lang = TapLocalizeManager.GetCurrentLanguageString();
32
- TapCloudSaveTracker.Instance.TrackInit();
33
- string cacheDir = Path.Combine(
34
- Application.persistentDataPath,
35
- "cloudsave_" + options.clientId
36
- );
37
- string deviceID = SystemInfo.deviceUniqueIdentifier;
38
- Task.Run(async () =>
39
- {
40
- TapTapAccount tapAccount = await TapTapLogin.Instance.GetCurrentTapAccount();
41
- string loginKid = "";
42
- string loginKey = "";
43
- if (tapAccount != null && !string.IsNullOrEmpty(tapAccount.openId))
44
- {
45
- loginKey = tapAccount.accessToken.macKey;
46
- loginKid = tapAccount.accessToken.kid;
47
- }
48
- Dictionary<string, object> loginData = new Dictionary<string, object>
49
- {
50
- { "kid", loginKid },
51
- { "key", loginKey },
52
- };
53
- int region = isRND ? 2 : 0;
54
- try
55
- {
56
- Dictionary<string, object> initConfig = new Dictionary<string, object>()
57
- {
58
- { "region", region },
59
- { "log_to_console", options.enableLog ? 1 : 0 },
60
- { "log_level", 3 },
61
- { "data_dir", cacheDir },
62
- { "client_id", options.clientId },
63
- { "client_token", options.clientToken },
64
- { "ua", TapHttpUtils.GenerateUserAgent() },
65
- { "lang", lang },
66
- { "platform", "PC" },
67
- { "device_id", deviceID },
68
- { "sdk_artifact", "Unity" },
69
- { "sdk_module_ver", TapTapCloudSave.Version },
70
- { "sdk_token", loginData },
71
- };
72
- Log(" start invoke TapSdkCloudSaveInitialize result ");
73
- // 初始化 C++ SDK 日志回调,将日志桥接到 Unity Debug.Log
74
- TapCloudSaveWrapper.InitLogger();
75
- TapCloudSaveWrapper.TapSdkCloudSaveSetLogLevel(1, options.enableLog ? 1 : 0);
76
- string config = JsonConvert.SerializeObject(initConfig);
77
- int initResult = TapCloudSaveWrapper.TapSdkCloudSaveInitialize(config);
78
- Log("TapSdkCloudSaveInitialize result = " + initResult);
79
- if (initResult < 0)
80
- {
81
- RunOnMainThread(() =>
82
- {
83
- if (currentSaveCallback != null && currentSaveCallback.Count > 0)
84
- {
85
- foreach (var callback in currentSaveCallback)
86
- {
87
- callback?.OnResult(TapCloudSaveResultCode.INIT_FAIL);
88
- }
89
- }
90
- });
91
- }
92
- else
93
- {
94
- lock (_lockObj)
95
- {
96
- _hasInitNative = true;
97
- }
98
- }
99
- }
100
- catch (Exception e)
101
- {
102
- Log("TapSdkCloudSaveInitialize error " + e.Message);
103
- }
104
- });
105
-
106
- EventManager.AddListener(EventManager.OnTapUserChanged, OnLoginInfoChanged);
107
- }
108
-
109
- public Task<ArchiveData> CreateArchive(
110
- ArchiveMetadata metadata,
111
- string archiveFilePath,
112
- string archiveCoverPath
113
- )
114
- {
115
- var taskSource = new TaskCompletionSource<ArchiveData>();
116
- CheckPCLaunchState();
117
- string seesionId = Guid.NewGuid().ToString();
118
- const string method = "createArchive";
119
- Task.Run(async () =>
120
- {
121
- bool hasInit = await CheckInitAndLoginState(method, seesionId);
122
- if (!hasInit)
123
- {
124
- taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
125
- return;
126
- }
127
- try
128
- {
129
- byte[] fileBytes = File.ReadAllBytes(archiveFilePath);
130
- byte[] coverData = null;
131
- if (!string.IsNullOrEmpty(archiveCoverPath))
132
- {
133
- coverData = File.ReadAllBytes(archiveCoverPath);
134
- }
135
- string metaValue = JsonConvert.SerializeObject(metadata);
136
- string result = TapCloudSaveWrapper.CreateArchive(
137
- metaValue,
138
- fileBytes,
139
- fileBytes.Length,
140
- coverData,
141
- coverData?.Length ?? 0
142
- );
143
- TapCloudSaveBaseResponse response =
144
- JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(result);
145
- if (response.success)
146
- {
147
- ArchiveData data = response.data.ToObject<ArchiveData>();
148
- TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
149
- var archiveData = new ArchiveData()
150
- {
151
- FileId = data.FileId,
152
- Uuid = data.Uuid,
153
- Name = metadata.Name,
154
- Summary = metadata.Summary,
155
- Extra = metadata.Extra,
156
- Playtime = metadata.Playtime,
157
- };
158
- taskSource.TrySetResult(archiveData);
159
- }
160
- else
161
- {
162
- try
163
- {
164
- TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
165
- Log(
166
- "createArchive failed error = " + JsonConvert.SerializeObject(error)
167
- );
168
- TapCloudSaveTracker.Instance.TrackFailure(
169
- method,
170
- seesionId,
171
- error.code,
172
- error.msg ?? ""
173
- );
174
- taskSource.TrySetException(new TapException(error.code, $"创建存档失败: {error.msg}"));
175
- }
176
- catch (Exception e)
177
- {
178
- TapCloudSaveTracker.Instance.TrackFailure(
179
- method,
180
- seesionId,
181
- -1,
182
- "创建存档失败: 数据解析异常"
183
- );
184
- taskSource.TrySetException(new TapException(-1, "创建存档失败: 数据解析异常"));
185
- }
186
- }
187
- }
188
- catch (Exception e)
189
- {
190
- string msg = $"创建存档失败: {e.Message}";
191
- TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
192
- taskSource.TrySetException(new TapException(-1, msg));
193
- }
194
- });
195
- return taskSource.Task;
196
- }
197
-
198
- public Task<ArchiveData> DeleteArchive(string archiveUuid)
199
- {
200
- var taskSource = new TaskCompletionSource<ArchiveData>();
201
- CheckPCLaunchState();
202
- string seesionId = Guid.NewGuid().ToString();
203
- const string method = "deleteArchive";
204
- Task.Run(async () =>
205
- {
206
- bool hasInit = await CheckInitAndLoginState(method, seesionId);
207
- if (!hasInit)
208
- {
209
- taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
210
- return;
211
- }
212
- try
213
- {
214
- string result = TapCloudSaveWrapper.DeleteArchive(archiveUuid);
215
- TapCloudSaveBaseResponse response =
216
- JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(result);
217
- if (response.success)
218
- {
219
- ArchiveData archiveData = response.data.ToObject<ArchiveData>();
220
- TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
221
- taskSource.TrySetResult(archiveData);
222
- }
223
- else
224
- {
225
- try
226
- {
227
- TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
228
- Log(
229
- "deleteArchive failed error = " + JsonConvert.SerializeObject(error)
230
- );
231
- TapCloudSaveTracker.Instance.TrackFailure(
232
- method,
233
- seesionId,
234
- error.code,
235
- error.msg ?? ""
236
- );
237
- taskSource.TrySetException(new TapException(error.code, $"删除存档失败: {error.msg}"));
238
- }
239
- catch (Exception e)
240
- {
241
- TapCloudSaveTracker.Instance.TrackFailure(
242
- method,
243
- seesionId,
244
- -1,
245
- "删除存档失败: 数据解析异常"
246
- );
247
- taskSource.TrySetException(new TapException(-1, "删除存档失败: 数据解析异常"));
248
- }
249
- }
250
- }
251
- catch (Exception e)
252
- {
253
- string msg = $"删除失败: {e.Message}";
254
- TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
255
- taskSource.TrySetException(new TapException(-1, msg));
256
- }
257
- });
258
- return taskSource.Task;
259
- }
260
-
261
- public Task<byte[]> GetArchiveCover(
262
- string archiveUuid,
263
- string archiveFileId
264
- )
265
- {
266
- var taskSource = new TaskCompletionSource<byte[]>();
267
- CheckPCLaunchState();
268
- string seesionId = Guid.NewGuid().ToString();
269
- const string method = "getArchiveCover";
270
- Task.Run(async () =>
271
- {
272
- bool hasInit = await CheckInitAndLoginState(method, seesionId);
273
- if (!hasInit)
274
- {
275
- taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
276
- return;
277
- }
278
- try
279
- {
280
- byte[] result = TapCloudSaveWrapper.GetArchiveCover(
281
- archiveUuid,
282
- archiveFileId,
283
- out int coverSize
284
- );
285
- if (coverSize >= 0)
286
- {
287
- taskSource.TrySetResult(result);
288
- TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
289
- }
290
- else
291
- {
292
- try
293
- {
294
- TapCloudSaveBaseResponse response =
295
- JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(
296
- Encoding.UTF8.GetString(result)
297
- );
298
- TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
299
- Log(
300
- "getArchiveCover failed error = " + JsonConvert.SerializeObject(error)
301
- );
302
- TapCloudSaveTracker.Instance.TrackFailure(
303
- method,
304
- seesionId,
305
- error.code,
306
- error.msg ?? ""
307
- );
308
- taskSource.TrySetException(new TapException(error.code, $"获取封面失败: {error.msg}"));
309
- }
310
- catch (Exception e)
311
- {
312
- TapCloudSaveTracker.Instance.TrackFailure(
313
- method,
314
- seesionId,
315
- -1,
316
- "获取封面失败: 数据解析异常"
317
- );
318
- taskSource.TrySetException(new TapException(-1, "获取封面失败: 数据解析异常"));
319
- }
320
- }
321
- }
322
- catch (Exception e)
323
- {
324
- string msg = $"获取封面失败: {e.Message}";
325
- TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
326
- taskSource.TrySetException(new TapException(-1, msg));
327
- }
328
- });
329
- return taskSource.Task;
330
- }
331
-
332
- public Task<byte[]> GetArchiveData(
333
- string archiveUuid,
334
- string archiveFileId
335
- )
336
- {
337
- var taskSource = new TaskCompletionSource<byte[]>();
338
- CheckPCLaunchState();
339
- string seesionId = Guid.NewGuid().ToString();
340
- const string method = "getArchiveData";
341
- Task.Run(async () =>
342
- {
343
- bool hasInit = await CheckInitAndLoginState(method, seesionId);
344
- if (!hasInit)
345
- {
346
- taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
347
- return;
348
- }
349
- try
350
- {
351
- byte[] result = TapCloudSaveWrapper.GetArchiveData(
352
- archiveUuid,
353
- archiveFileId,
354
- out int fileSize
355
- );
356
- if (fileSize >= 0)
357
- {
358
- taskSource.TrySetResult(result);
359
- TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
360
- }
361
- else
362
- {
363
- try
364
- {
365
- TapCloudSaveBaseResponse response =
366
- JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(
367
- Encoding.UTF8.GetString(result)
368
- );
369
- TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
370
- Log(
371
- "getArchiveData failed error = " + JsonConvert.SerializeObject(error)
372
- );
373
- TapCloudSaveTracker.Instance.TrackFailure(
374
- method,
375
- seesionId,
376
- error.code,
377
- error.msg ?? ""
378
- );
379
- taskSource.TrySetException(new TapException(error.code, $"获取存档失败: {error.msg}"));
380
- }
381
- catch (Exception e)
382
- {
383
- TapCloudSaveTracker.Instance.TrackFailure(
384
- method,
385
- seesionId,
386
- -1,
387
- "获取存档失败: 数据解析异常"
388
- );
389
- taskSource.TrySetException(new TapException(-1, "获取存档失败: 数据解析异常"));
390
- }
391
- }
392
- }
393
- catch (Exception e)
394
- {
395
- string msg = $"获取存档失败: {e.Message}";
396
- TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
397
- taskSource.TrySetException(new TapException(-1, msg));
398
- }
399
- });
400
- return taskSource.Task;
401
- }
402
-
403
- public Task<List<ArchiveData>> GetArchiveList()
404
- {
405
- var taskSource = new TaskCompletionSource<List<ArchiveData>>();
406
- CheckPCLaunchState();
407
- string seesionId = Guid.NewGuid().ToString();
408
- const string method = "getArchiveList";
409
- Task.Run(async () =>
410
- {
411
- bool hasInit = await CheckInitAndLoginState(method, seesionId);
412
- if (!hasInit)
413
- {
414
- taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
415
- return;
416
- }
417
- try
418
- {
419
- string result = TapCloudSaveWrapper.GetArchiveList();
420
- TapCloudSaveBaseResponse response =
421
- JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(result);
422
- if (response.success)
423
- {
424
- TapCloudSaveArchiveListResponse archiveDatas =
425
- response.data.ToObject<TapCloudSaveArchiveListResponse>();
426
- TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
427
- taskSource.TrySetResult(archiveDatas.saves);
428
- }
429
- else
430
- {
431
- try
432
- {
433
- TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
434
- Log(
435
- "getArchiveList failed error = " + JsonConvert.SerializeObject(error)
436
- );
437
- TapCloudSaveTracker.Instance.TrackFailure(
438
- method,
439
- seesionId,
440
- error.code,
441
- error.msg ?? ""
442
- );
443
- taskSource.TrySetException(new TapException(error.code, $"获取存档列表失败: {error.msg}"));
444
- }
445
- catch (Exception e)
446
- {
447
- TapCloudSaveTracker.Instance.TrackFailure(
448
- method,
449
- seesionId,
450
- -1,
451
- "获取存档列表失败: 数据解析异常"
452
- );
453
- taskSource.TrySetException(new TapException(-1, "获取存档列表失败: 数据解析异常"));
454
- }
455
- }
456
- }
457
- catch (Exception e)
458
- {
459
- string msg = $"获取存档列表失败: {e.Message}";
460
- TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
461
- taskSource.TrySetException(new TapException(-1, msg));
462
- }
463
- });
464
- return taskSource.Task;
465
- }
466
-
467
- public void RegisterCloudSaveCallback(ITapCloudSaveCallback callback)
468
- {
469
- string seesionId = Guid.NewGuid().ToString();
470
- const string method = "registerCloudSaveCallback";
471
- TapCloudSaveTracker.Instance.TrackStart(method, seesionId);
472
- if (currentSaveCallback == null)
473
- {
474
- currentSaveCallback = new List<ITapCloudSaveCallback>();
475
- }
476
- if (!currentSaveCallback.Contains(callback))
477
- {
478
- TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
479
- currentSaveCallback.Add(callback);
480
- Log($"RegisterCloudSaveCallback: Added callback. Total callbacks: {currentSaveCallback.Count}");
481
- }
482
- else
483
- {
484
- TapCloudSaveTracker.Instance.TrackFailure(
485
- method,
486
- seesionId,
487
- errorMessage: "callback has already registered"
488
- );
489
- Log("RegisterCloudSaveCallback: Callback already registered");
490
- }
491
- }
492
-
493
- public void UnregisterCloudSaveCallback(ITapCloudSaveCallback callback)
494
- {
495
- string seesionId = Guid.NewGuid().ToString();
496
- const string method = "unregisterCloudSaveCallback";
497
- TapCloudSaveTracker.Instance.TrackStart(method, seesionId);
498
-
499
- if (currentSaveCallback != null && callback != null)
500
- {
501
- if (currentSaveCallback.Contains(callback))
502
- {
503
- currentSaveCallback.Remove(callback);
504
- TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
505
- Log($"UnregisterCloudSaveCallback: Removed callback. Remaining callbacks: {currentSaveCallback.Count}");
506
- }
507
- else
508
- {
509
- TapCloudSaveTracker.Instance.TrackFailure(
510
- method,
511
- seesionId,
512
- errorMessage: "callback not found"
513
- );
514
- Log("UnregisterCloudSaveCallback: Callback not found");
515
- }
516
- }
517
- else
518
- {
519
- TapCloudSaveTracker.Instance.TrackFailure(
520
- method,
521
- seesionId,
522
- errorMessage: "callback or callback list is null"
523
- );
524
- Log("UnregisterCloudSaveCallback: Callback or callback list is null");
525
- }
526
- }
527
-
528
- public Task<ArchiveData> UpdateArchive(
529
- string archiveUuid,
530
- ArchiveMetadata metadata,
531
- string archiveFilePath,
532
- string archiveCoverPath
533
- )
534
- {
535
- var taskSource = new TaskCompletionSource<ArchiveData>();
536
- CheckPCLaunchState();
537
- string seesionId = Guid.NewGuid().ToString();
538
- const string method = "updateArchive";
539
- Task.Run(async () =>
540
- {
541
- bool hasInit = await CheckInitAndLoginState(method, seesionId);
542
- if (!hasInit)
543
- {
544
- taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
545
- return;
546
- }
547
- try
548
- {
549
- byte[] fileBytes = File.ReadAllBytes(archiveFilePath);
550
- byte[] coverData = null;
551
- if (!string.IsNullOrEmpty(archiveCoverPath))
552
- {
553
- coverData = File.ReadAllBytes(archiveCoverPath);
554
- }
555
- string metaValue = JsonConvert.SerializeObject(metadata);
556
- string result = TapCloudSaveWrapper.UpdateArchive(
557
- archiveUuid,
558
- metaValue,
559
- fileBytes,
560
- fileBytes.Length,
561
- coverData,
562
- coverData?.Length ?? 0
563
- );
564
- TapCloudSaveBaseResponse response =
565
- JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(result);
566
- if (response.success)
567
- {
568
- ArchiveData data = response.data.ToObject<ArchiveData>();
569
- TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
570
- taskSource.TrySetResult(data);
571
- }
572
- else
573
- {
574
- try
575
- {
576
- TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
577
- Log(
578
- "updateArchive failed error = " + JsonConvert.SerializeObject(error)
579
- );
580
- TapCloudSaveTracker.Instance.TrackFailure(
581
- method,
582
- seesionId,
583
- error.code,
584
- error.msg ?? ""
585
- );
586
- taskSource.TrySetException(new TapException(error.code, $"更新存档失败: {error.msg}"));
587
- }
588
- catch (Exception e)
589
- {
590
- TapCloudSaveTracker.Instance.TrackFailure(
591
- method,
592
- seesionId,
593
- -1,
594
- "更新存档失败: 数据解析异常"
595
- );
596
- taskSource.TrySetException(new TapException(-1, "更新存档失败: 数据解析异常"));
597
- }
598
- }
599
- }
600
- catch (Exception e)
601
- {
602
- string msg = $"更新存档失败: {e.Message}";
603
- TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
604
- taskSource.TrySetException(new TapException(-1, msg));
605
- }
606
- });
607
- return taskSource.Task;
608
- }
609
-
610
- private async Task<bool> CheckInitAndLoginState(string method, string sessionId)
611
- {
612
- if (TapCoreStandalone.CheckInitState())
613
- {
614
- lock (_lockObj)
615
- {
616
- if (!_hasInitNative)
617
- {
618
- Log("not init success, so return", true);
619
- return false;
620
- }
621
- }
622
- TapCloudSaveTracker.Instance.TrackStart(method, sessionId);
623
- TapTapAccount tapAccount = await TapTapLogin.Instance.GetCurrentTapAccount();
624
- if (tapAccount != null && !string.IsNullOrEmpty(tapAccount.openId))
625
- {
626
- return true;
627
- }
628
- else
629
- {
630
- if (currentSaveCallback != null && currentSaveCallback.Count > 0)
631
- {
632
- foreach (var callback in currentSaveCallback)
633
- {
634
- callback?.OnResult(TapCloudSaveResultCode.NEED_LOGIN);
635
- }
636
- }
637
- TapCloudSaveTracker.Instance.TrackFailure(method, sessionId, -1, "not login");
638
- return false;
639
- }
640
- }
641
- return false;
642
- }
643
-
644
- /// <summary>
645
- /// 检查是否通过 PC 启动校验
646
- /// </summary>
647
- private void CheckPCLaunchState()
648
- {
649
- #if UNITY_STANDALONE_WIN
650
- if (!TapClientStandalone.isPassedInLaunchedFromTapTapPCCheck())
651
- {
652
- throw new Exception("TapCloudSave method must be invoked after isLaunchedFromTapTapPC succeed");
653
- }
654
- #endif
655
- }
656
-
657
- internal void OnLoginInfoChanged(object data)
658
- {
659
- lock (_lockObj)
660
- {
661
- if (_hasInitNative)
662
- {
663
- Task.Run(async () =>
664
- {
665
- TapTapAccount tapAccount =
666
- await TapTapLogin.Instance.GetCurrentTapAccount();
667
- string loginKid = "";
668
- string loginKey = "";
669
- if (tapAccount != null && !string.IsNullOrEmpty(tapAccount.openId))
670
- {
671
- loginKey = tapAccount.accessToken.macKey;
672
- loginKid = tapAccount.accessToken.kid;
673
- }
674
- Dictionary<string, object> loginData = new Dictionary<string, object>
675
- {
676
- { "kid", loginKid },
677
- { "key", loginKey },
678
- };
679
- int result = TapCloudSaveWrapper.TapSdkCloudSaveUpdateAccessToken(
680
- JsonConvert.SerializeObject(loginData)
681
- );
682
- Log("update login msg result = " + result);
683
- });
684
- }
685
- }
686
- }
687
-
688
- private void RunOnMainThread(Action action)
689
- {
690
- TapLoom.QueueOnMainThread(action);
691
- }
692
-
693
- private void Log(string msg, bool isError = false)
694
- {
695
- if (cloudSaveLog == null)
696
- {
697
- cloudSaveLog = new TapLog("TapCloudSave");
698
- }
699
- if (!string.IsNullOrEmpty(msg))
700
- {
701
- if (isError)
702
- {
703
- cloudSaveLog.Error(msg);
704
- }
705
- else
706
- {
707
- cloudSaveLog.Log(msg);
708
- }
709
- }
710
- }
711
- }
712
- }
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.IO;
4
+ using System.Text;
5
+ using System.Threading.Tasks;
6
+ using Newtonsoft.Json;
7
+ using TapSDK.CloudSave.Internal;
8
+ using TapSDK.Core;
9
+ using TapSDK.Core.Internal.Log;
10
+ using TapSDK.Core.Internal.Utils;
11
+ using TapSDK.Core.Standalone;
12
+ using TapSDK.Core.Standalone.Internal;
13
+ using TapSDK.Core.Standalone.Internal.Http;
14
+ using TapSDK.Login;
15
+ using UnityEngine;
16
+
17
+ namespace TapSDK.CloudSave.Standalone
18
+ {
19
+ public class TapCloudSaveStandalone : ITapCloudSaveBridge
20
+ {
21
+ private List<ITapCloudSaveCallback> currentSaveCallback = null;
22
+ private static readonly bool isRND = false;
23
+ private bool _hasInitNative = false;
24
+ private object _lockObj = new object();
25
+
26
+ private TapLog cloudSaveLog;
27
+
28
+ public void Init(TapTapSdkOptions options)
29
+ {
30
+ Log("TapCloudSave start init");
31
+ string lang = TapLocalizeManager.GetCurrentLanguageString();
32
+ TapCloudSaveTracker.Instance.TrackInit();
33
+ string cacheDir = Path.Combine(
34
+ Application.persistentDataPath,
35
+ "cloudsave_" + options.clientId
36
+ );
37
+ string deviceID = SystemInfo.deviceUniqueIdentifier;
38
+ Task.Run(async () =>
39
+ {
40
+ TapTapAccount tapAccount = await TapTapLogin.Instance.GetCurrentTapAccount();
41
+ string loginKid = "";
42
+ string loginKey = "";
43
+ if (tapAccount != null && !string.IsNullOrEmpty(tapAccount.openId))
44
+ {
45
+ loginKey = tapAccount.accessToken.macKey;
46
+ loginKid = tapAccount.accessToken.kid;
47
+ }
48
+ Dictionary<string, object> loginData = new Dictionary<string, object>
49
+ {
50
+ { "kid", loginKid },
51
+ { "key", loginKey },
52
+ };
53
+ int region = isRND ? 2 : 0;
54
+ try
55
+ {
56
+ Dictionary<string, object> initConfig = new Dictionary<string, object>()
57
+ {
58
+ { "region", region },
59
+ { "log_to_console", options.enableLog ? 1 : 0 },
60
+ { "log_level", 3 },
61
+ { "data_dir", cacheDir },
62
+ { "client_id", options.clientId },
63
+ { "client_token", options.clientToken },
64
+ { "ua", TapHttpUtils.GenerateUserAgent() },
65
+ { "lang", lang },
66
+ { "platform", "PC" },
67
+ { "device_id", deviceID },
68
+ { "sdk_artifact", "Unity" },
69
+ { "sdk_module_ver", TapTapCloudSave.Version },
70
+ { "sdk_token", loginData },
71
+ };
72
+ Log(" start invoke TapSdkCloudSaveInitialize result ");
73
+ // 初始化 C++ SDK 日志回调,将日志桥接到 Unity Debug.Log
74
+ TapCloudSaveWrapper.InitLogger();
75
+ TapCloudSaveWrapper.TapSdkCloudSaveSetLogLevel(1, options.enableLog ? 1 : 0);
76
+ string config = JsonConvert.SerializeObject(initConfig);
77
+ int initResult = TapCloudSaveWrapper.TapSdkCloudSaveInitialize(config);
78
+ Log("TapSdkCloudSaveInitialize result = " + initResult);
79
+ if (initResult < 0)
80
+ {
81
+ RunOnMainThread(() =>
82
+ {
83
+ if (currentSaveCallback != null && currentSaveCallback.Count > 0)
84
+ {
85
+ foreach (var callback in currentSaveCallback)
86
+ {
87
+ callback?.OnResult(TapCloudSaveResultCode.INIT_FAIL);
88
+ }
89
+ }
90
+ });
91
+ }
92
+ else
93
+ {
94
+ lock (_lockObj)
95
+ {
96
+ _hasInitNative = true;
97
+ }
98
+ }
99
+ }
100
+ catch (Exception e)
101
+ {
102
+ Log("TapSdkCloudSaveInitialize error " + e.Message);
103
+ }
104
+ });
105
+
106
+ EventManager.AddListener(EventManager.OnTapUserChanged, OnLoginInfoChanged);
107
+ }
108
+
109
+ public Task<ArchiveData> CreateArchive(
110
+ ArchiveMetadata metadata,
111
+ string archiveFilePath,
112
+ string archiveCoverPath
113
+ )
114
+ {
115
+ var taskSource = new TaskCompletionSource<ArchiveData>();
116
+ CheckPCLaunchState();
117
+ string seesionId = Guid.NewGuid().ToString();
118
+ const string method = "createArchive";
119
+ Task.Run(async () =>
120
+ {
121
+ bool hasInit = await CheckInitAndLoginState(method, seesionId);
122
+ if (!hasInit)
123
+ {
124
+ taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
125
+ return;
126
+ }
127
+ try
128
+ {
129
+ byte[] fileBytes = File.ReadAllBytes(archiveFilePath);
130
+ byte[] coverData = null;
131
+ if (!string.IsNullOrEmpty(archiveCoverPath))
132
+ {
133
+ coverData = File.ReadAllBytes(archiveCoverPath);
134
+ }
135
+ string metaValue = JsonConvert.SerializeObject(metadata);
136
+ string result = TapCloudSaveWrapper.CreateArchive(
137
+ metaValue,
138
+ fileBytes,
139
+ fileBytes.Length,
140
+ coverData,
141
+ coverData?.Length ?? 0
142
+ );
143
+ TapCloudSaveBaseResponse response =
144
+ JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(result);
145
+ if (response.success)
146
+ {
147
+ ArchiveData data = response.data.ToObject<ArchiveData>();
148
+ TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
149
+ var archiveData = new ArchiveData()
150
+ {
151
+ FileId = data.FileId,
152
+ Uuid = data.Uuid,
153
+ Name = metadata.Name,
154
+ Summary = metadata.Summary,
155
+ Extra = metadata.Extra,
156
+ Playtime = metadata.Playtime,
157
+ };
158
+ taskSource.TrySetResult(archiveData);
159
+ }
160
+ else
161
+ {
162
+ try
163
+ {
164
+ TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
165
+ Log(
166
+ "createArchive failed error = " + JsonConvert.SerializeObject(error)
167
+ );
168
+ TapCloudSaveTracker.Instance.TrackFailure(
169
+ method,
170
+ seesionId,
171
+ error.code,
172
+ error.msg ?? ""
173
+ );
174
+ taskSource.TrySetException(new TapException(error.code, $"创建存档失败: {error.msg}"));
175
+ }
176
+ catch (Exception e)
177
+ {
178
+ TapCloudSaveTracker.Instance.TrackFailure(
179
+ method,
180
+ seesionId,
181
+ -1,
182
+ "创建存档失败: 数据解析异常"
183
+ );
184
+ taskSource.TrySetException(new TapException(-1, "创建存档失败: 数据解析异常"));
185
+ }
186
+ }
187
+ }
188
+ catch (Exception e)
189
+ {
190
+ string msg = $"创建存档失败: {e.Message}";
191
+ TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
192
+ taskSource.TrySetException(new TapException(-1, msg));
193
+ }
194
+ });
195
+ return taskSource.Task;
196
+ }
197
+
198
+ public Task<ArchiveData> DeleteArchive(string archiveUuid)
199
+ {
200
+ var taskSource = new TaskCompletionSource<ArchiveData>();
201
+ CheckPCLaunchState();
202
+ string seesionId = Guid.NewGuid().ToString();
203
+ const string method = "deleteArchive";
204
+ Task.Run(async () =>
205
+ {
206
+ bool hasInit = await CheckInitAndLoginState(method, seesionId);
207
+ if (!hasInit)
208
+ {
209
+ taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
210
+ return;
211
+ }
212
+ try
213
+ {
214
+ string result = TapCloudSaveWrapper.DeleteArchive(archiveUuid);
215
+ TapCloudSaveBaseResponse response =
216
+ JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(result);
217
+ if (response.success)
218
+ {
219
+ ArchiveData archiveData = response.data.ToObject<ArchiveData>();
220
+ TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
221
+ taskSource.TrySetResult(archiveData);
222
+ }
223
+ else
224
+ {
225
+ try
226
+ {
227
+ TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
228
+ Log(
229
+ "deleteArchive failed error = " + JsonConvert.SerializeObject(error)
230
+ );
231
+ TapCloudSaveTracker.Instance.TrackFailure(
232
+ method,
233
+ seesionId,
234
+ error.code,
235
+ error.msg ?? ""
236
+ );
237
+ taskSource.TrySetException(new TapException(error.code, $"删除存档失败: {error.msg}"));
238
+ }
239
+ catch (Exception e)
240
+ {
241
+ TapCloudSaveTracker.Instance.TrackFailure(
242
+ method,
243
+ seesionId,
244
+ -1,
245
+ "删除存档失败: 数据解析异常"
246
+ );
247
+ taskSource.TrySetException(new TapException(-1, "删除存档失败: 数据解析异常"));
248
+ }
249
+ }
250
+ }
251
+ catch (Exception e)
252
+ {
253
+ string msg = $"删除失败: {e.Message}";
254
+ TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
255
+ taskSource.TrySetException(new TapException(-1, msg));
256
+ }
257
+ });
258
+ return taskSource.Task;
259
+ }
260
+
261
+ public Task<byte[]> GetArchiveCover(
262
+ string archiveUuid,
263
+ string archiveFileId
264
+ )
265
+ {
266
+ var taskSource = new TaskCompletionSource<byte[]>();
267
+ CheckPCLaunchState();
268
+ string seesionId = Guid.NewGuid().ToString();
269
+ const string method = "getArchiveCover";
270
+ Task.Run(async () =>
271
+ {
272
+ bool hasInit = await CheckInitAndLoginState(method, seesionId);
273
+ if (!hasInit)
274
+ {
275
+ taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
276
+ return;
277
+ }
278
+ try
279
+ {
280
+ byte[] result = TapCloudSaveWrapper.GetArchiveCover(
281
+ archiveUuid,
282
+ archiveFileId,
283
+ out int coverSize
284
+ );
285
+ if (coverSize >= 0)
286
+ {
287
+ taskSource.TrySetResult(result);
288
+ TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
289
+ }
290
+ else
291
+ {
292
+ try
293
+ {
294
+ TapCloudSaveBaseResponse response =
295
+ JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(
296
+ Encoding.UTF8.GetString(result)
297
+ );
298
+ TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
299
+ Log(
300
+ "getArchiveCover failed error = " + JsonConvert.SerializeObject(error)
301
+ );
302
+ TapCloudSaveTracker.Instance.TrackFailure(
303
+ method,
304
+ seesionId,
305
+ error.code,
306
+ error.msg ?? ""
307
+ );
308
+ taskSource.TrySetException(new TapException(error.code, $"获取封面失败: {error.msg}"));
309
+ }
310
+ catch (Exception e)
311
+ {
312
+ TapCloudSaveTracker.Instance.TrackFailure(
313
+ method,
314
+ seesionId,
315
+ -1,
316
+ "获取封面失败: 数据解析异常"
317
+ );
318
+ taskSource.TrySetException(new TapException(-1, "获取封面失败: 数据解析异常"));
319
+ }
320
+ }
321
+ }
322
+ catch (Exception e)
323
+ {
324
+ string msg = $"获取封面失败: {e.Message}";
325
+ TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
326
+ taskSource.TrySetException(new TapException(-1, msg));
327
+ }
328
+ });
329
+ return taskSource.Task;
330
+ }
331
+
332
+ public Task<byte[]> GetArchiveData(
333
+ string archiveUuid,
334
+ string archiveFileId
335
+ )
336
+ {
337
+ var taskSource = new TaskCompletionSource<byte[]>();
338
+ CheckPCLaunchState();
339
+ string seesionId = Guid.NewGuid().ToString();
340
+ const string method = "getArchiveData";
341
+ Task.Run(async () =>
342
+ {
343
+ bool hasInit = await CheckInitAndLoginState(method, seesionId);
344
+ if (!hasInit)
345
+ {
346
+ taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
347
+ return;
348
+ }
349
+ try
350
+ {
351
+ byte[] result = TapCloudSaveWrapper.GetArchiveData(
352
+ archiveUuid,
353
+ archiveFileId,
354
+ out int fileSize
355
+ );
356
+ if (fileSize >= 0)
357
+ {
358
+ taskSource.TrySetResult(result);
359
+ TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
360
+ }
361
+ else
362
+ {
363
+ try
364
+ {
365
+ TapCloudSaveBaseResponse response =
366
+ JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(
367
+ Encoding.UTF8.GetString(result)
368
+ );
369
+ TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
370
+ Log(
371
+ "getArchiveData failed error = " + JsonConvert.SerializeObject(error)
372
+ );
373
+ TapCloudSaveTracker.Instance.TrackFailure(
374
+ method,
375
+ seesionId,
376
+ error.code,
377
+ error.msg ?? ""
378
+ );
379
+ taskSource.TrySetException(new TapException(error.code, $"获取存档失败: {error.msg}"));
380
+ }
381
+ catch (Exception e)
382
+ {
383
+ TapCloudSaveTracker.Instance.TrackFailure(
384
+ method,
385
+ seesionId,
386
+ -1,
387
+ "获取存档失败: 数据解析异常"
388
+ );
389
+ taskSource.TrySetException(new TapException(-1, "获取存档失败: 数据解析异常"));
390
+ }
391
+ }
392
+ }
393
+ catch (Exception e)
394
+ {
395
+ string msg = $"获取存档失败: {e.Message}";
396
+ TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
397
+ taskSource.TrySetException(new TapException(-1, msg));
398
+ }
399
+ });
400
+ return taskSource.Task;
401
+ }
402
+
403
+ public Task<List<ArchiveData>> GetArchiveList()
404
+ {
405
+ var taskSource = new TaskCompletionSource<List<ArchiveData>>();
406
+ CheckPCLaunchState();
407
+ string seesionId = Guid.NewGuid().ToString();
408
+ const string method = "getArchiveList";
409
+ Task.Run(async () =>
410
+ {
411
+ bool hasInit = await CheckInitAndLoginState(method, seesionId);
412
+ if (!hasInit)
413
+ {
414
+ taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
415
+ return;
416
+ }
417
+ try
418
+ {
419
+ string result = TapCloudSaveWrapper.GetArchiveList();
420
+ TapCloudSaveBaseResponse response =
421
+ JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(result);
422
+ if (response.success)
423
+ {
424
+ TapCloudSaveArchiveListResponse archiveDatas =
425
+ response.data.ToObject<TapCloudSaveArchiveListResponse>();
426
+ TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
427
+ taskSource.TrySetResult(archiveDatas.saves);
428
+ }
429
+ else
430
+ {
431
+ try
432
+ {
433
+ TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
434
+ Log(
435
+ "getArchiveList failed error = " + JsonConvert.SerializeObject(error)
436
+ );
437
+ TapCloudSaveTracker.Instance.TrackFailure(
438
+ method,
439
+ seesionId,
440
+ error.code,
441
+ error.msg ?? ""
442
+ );
443
+ taskSource.TrySetException(new TapException(error.code, $"获取存档列表失败: {error.msg}"));
444
+ }
445
+ catch (Exception e)
446
+ {
447
+ TapCloudSaveTracker.Instance.TrackFailure(
448
+ method,
449
+ seesionId,
450
+ -1,
451
+ "获取存档列表失败: 数据解析异常"
452
+ );
453
+ taskSource.TrySetException(new TapException(-1, "获取存档列表失败: 数据解析异常"));
454
+ }
455
+ }
456
+ }
457
+ catch (Exception e)
458
+ {
459
+ string msg = $"获取存档列表失败: {e.Message}";
460
+ TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
461
+ taskSource.TrySetException(new TapException(-1, msg));
462
+ }
463
+ });
464
+ return taskSource.Task;
465
+ }
466
+
467
+ public void RegisterCloudSaveCallback(ITapCloudSaveCallback callback)
468
+ {
469
+ string seesionId = Guid.NewGuid().ToString();
470
+ const string method = "registerCloudSaveCallback";
471
+ TapCloudSaveTracker.Instance.TrackStart(method, seesionId);
472
+ if (currentSaveCallback == null)
473
+ {
474
+ currentSaveCallback = new List<ITapCloudSaveCallback>();
475
+ }
476
+ if (!currentSaveCallback.Contains(callback))
477
+ {
478
+ TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
479
+ currentSaveCallback.Add(callback);
480
+ Log($"RegisterCloudSaveCallback: Added callback. Total callbacks: {currentSaveCallback.Count}");
481
+ }
482
+ else
483
+ {
484
+ TapCloudSaveTracker.Instance.TrackFailure(
485
+ method,
486
+ seesionId,
487
+ errorMessage: "callback has already registered"
488
+ );
489
+ Log("RegisterCloudSaveCallback: Callback already registered");
490
+ }
491
+ }
492
+
493
+ public void UnregisterCloudSaveCallback(ITapCloudSaveCallback callback)
494
+ {
495
+ string seesionId = Guid.NewGuid().ToString();
496
+ const string method = "unregisterCloudSaveCallback";
497
+ TapCloudSaveTracker.Instance.TrackStart(method, seesionId);
498
+
499
+ if (currentSaveCallback != null && callback != null)
500
+ {
501
+ if (currentSaveCallback.Contains(callback))
502
+ {
503
+ currentSaveCallback.Remove(callback);
504
+ TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
505
+ Log($"UnregisterCloudSaveCallback: Removed callback. Remaining callbacks: {currentSaveCallback.Count}");
506
+ }
507
+ else
508
+ {
509
+ TapCloudSaveTracker.Instance.TrackFailure(
510
+ method,
511
+ seesionId,
512
+ errorMessage: "callback not found"
513
+ );
514
+ Log("UnregisterCloudSaveCallback: Callback not found");
515
+ }
516
+ }
517
+ else
518
+ {
519
+ TapCloudSaveTracker.Instance.TrackFailure(
520
+ method,
521
+ seesionId,
522
+ errorMessage: "callback or callback list is null"
523
+ );
524
+ Log("UnregisterCloudSaveCallback: Callback or callback list is null");
525
+ }
526
+ }
527
+
528
+ public Task<ArchiveData> UpdateArchive(
529
+ string archiveUuid,
530
+ ArchiveMetadata metadata,
531
+ string archiveFilePath,
532
+ string archiveCoverPath
533
+ )
534
+ {
535
+ var taskSource = new TaskCompletionSource<ArchiveData>();
536
+ CheckPCLaunchState();
537
+ string seesionId = Guid.NewGuid().ToString();
538
+ const string method = "updateArchive";
539
+ Task.Run(async () =>
540
+ {
541
+ bool hasInit = await CheckInitAndLoginState(method, seesionId);
542
+ if (!hasInit)
543
+ {
544
+ taskSource.TrySetException(new TapException(-1, "Init or login state check failed"));
545
+ return;
546
+ }
547
+ try
548
+ {
549
+ byte[] fileBytes = File.ReadAllBytes(archiveFilePath);
550
+ byte[] coverData = null;
551
+ if (!string.IsNullOrEmpty(archiveCoverPath))
552
+ {
553
+ coverData = File.ReadAllBytes(archiveCoverPath);
554
+ }
555
+ string metaValue = JsonConvert.SerializeObject(metadata);
556
+ string result = TapCloudSaveWrapper.UpdateArchive(
557
+ archiveUuid,
558
+ metaValue,
559
+ fileBytes,
560
+ fileBytes.Length,
561
+ coverData,
562
+ coverData?.Length ?? 0
563
+ );
564
+ TapCloudSaveBaseResponse response =
565
+ JsonConvert.DeserializeObject<TapCloudSaveBaseResponse>(result);
566
+ if (response.success)
567
+ {
568
+ ArchiveData data = response.data.ToObject<ArchiveData>();
569
+ TapCloudSaveTracker.Instance.TrackSuccess(method, seesionId);
570
+ taskSource.TrySetResult(data);
571
+ }
572
+ else
573
+ {
574
+ try
575
+ {
576
+ TapCloudSaveError error = response.data.ToObject<TapCloudSaveError>();
577
+ Log(
578
+ "updateArchive failed error = " + JsonConvert.SerializeObject(error)
579
+ );
580
+ TapCloudSaveTracker.Instance.TrackFailure(
581
+ method,
582
+ seesionId,
583
+ error.code,
584
+ error.msg ?? ""
585
+ );
586
+ taskSource.TrySetException(new TapException(error.code, $"更新存档失败: {error.msg}"));
587
+ }
588
+ catch (Exception e)
589
+ {
590
+ TapCloudSaveTracker.Instance.TrackFailure(
591
+ method,
592
+ seesionId,
593
+ -1,
594
+ "更新存档失败: 数据解析异常"
595
+ );
596
+ taskSource.TrySetException(new TapException(-1, "更新存档失败: 数据解析异常"));
597
+ }
598
+ }
599
+ }
600
+ catch (Exception e)
601
+ {
602
+ string msg = $"更新存档失败: {e.Message}";
603
+ TapCloudSaveTracker.Instance.TrackFailure(method, seesionId, -1, msg);
604
+ taskSource.TrySetException(new TapException(-1, msg));
605
+ }
606
+ });
607
+ return taskSource.Task;
608
+ }
609
+
610
+ private async Task<bool> CheckInitAndLoginState(string method, string sessionId)
611
+ {
612
+ if (TapCoreStandalone.CheckInitState())
613
+ {
614
+ lock (_lockObj)
615
+ {
616
+ if (!_hasInitNative)
617
+ {
618
+ Log("not init success, so return", true);
619
+ return false;
620
+ }
621
+ }
622
+ TapCloudSaveTracker.Instance.TrackStart(method, sessionId);
623
+ TapTapAccount tapAccount = await TapTapLogin.Instance.GetCurrentTapAccount();
624
+ if (tapAccount != null && !string.IsNullOrEmpty(tapAccount.openId))
625
+ {
626
+ return true;
627
+ }
628
+ else
629
+ {
630
+ if (currentSaveCallback != null && currentSaveCallback.Count > 0)
631
+ {
632
+ foreach (var callback in currentSaveCallback)
633
+ {
634
+ callback?.OnResult(TapCloudSaveResultCode.NEED_LOGIN);
635
+ }
636
+ }
637
+ TapCloudSaveTracker.Instance.TrackFailure(method, sessionId, -1, "not login");
638
+ return false;
639
+ }
640
+ }
641
+ return false;
642
+ }
643
+
644
+ /// <summary>
645
+ /// 检查是否通过 PC 启动校验
646
+ /// </summary>
647
+ private void CheckPCLaunchState()
648
+ {
649
+ #if UNITY_STANDALONE_WIN
650
+ if (!TapClientStandalone.isPassedInLaunchedFromTapTapPCCheck())
651
+ {
652
+ throw new Exception("TapCloudSave method must be invoked after isLaunchedFromTapTapPC succeed");
653
+ }
654
+ #endif
655
+ }
656
+
657
+ internal void OnLoginInfoChanged(object data)
658
+ {
659
+ lock (_lockObj)
660
+ {
661
+ if (_hasInitNative)
662
+ {
663
+ Task.Run(async () =>
664
+ {
665
+ TapTapAccount tapAccount =
666
+ await TapTapLogin.Instance.GetCurrentTapAccount();
667
+ string loginKid = "";
668
+ string loginKey = "";
669
+ if (tapAccount != null && !string.IsNullOrEmpty(tapAccount.openId))
670
+ {
671
+ loginKey = tapAccount.accessToken.macKey;
672
+ loginKid = tapAccount.accessToken.kid;
673
+ }
674
+ Dictionary<string, object> loginData = new Dictionary<string, object>
675
+ {
676
+ { "kid", loginKid },
677
+ { "key", loginKey },
678
+ };
679
+ int result = TapCloudSaveWrapper.TapSdkCloudSaveUpdateAccessToken(
680
+ JsonConvert.SerializeObject(loginData)
681
+ );
682
+ Log("update login msg result = " + result);
683
+ });
684
+ }
685
+ }
686
+ }
687
+
688
+ private void RunOnMainThread(Action action)
689
+ {
690
+ TapLoom.QueueOnMainThread(action);
691
+ }
692
+
693
+ private void Log(string msg, bool isError = false)
694
+ {
695
+ if (cloudSaveLog == null)
696
+ {
697
+ cloudSaveLog = new TapLog("TapCloudSave");
698
+ }
699
+ if (!string.IsNullOrEmpty(msg))
700
+ {
701
+ if (isError)
702
+ {
703
+ cloudSaveLog.Error(msg);
704
+ }
705
+ else
706
+ {
707
+ cloudSaveLog.Log(msg);
708
+ }
709
+ }
710
+ }
711
+ }
712
+ }