232 lines
7.2 KiB
C#
232 lines
7.2 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using game.PlayerDataStorage;
|
|
|
|
internal class KVMgr : MonoBehaviour
|
|
{
|
|
private static KVMgr instance;
|
|
private KVPlayerSaveStore store;
|
|
private CancellationTokenSource tokenSource;
|
|
|
|
private void Awake()
|
|
{
|
|
instance = this;
|
|
tokenSource = new CancellationTokenSource();
|
|
UpdateUserDataValue(tokenSource.Token);
|
|
}
|
|
|
|
internal static void Bind(KVPlayerSaveStore original)
|
|
{
|
|
if (instance != null)
|
|
{
|
|
instance.store = original;
|
|
}
|
|
}
|
|
|
|
internal static void Unbind(KVPlayerSaveStore original)
|
|
{
|
|
if (instance != null && ReferenceEquals(instance.store, original))
|
|
{
|
|
instance.store = null;
|
|
}
|
|
}
|
|
|
|
internal static void Stop(KVPlayerSaveStore original)
|
|
{
|
|
if (instance != null && ReferenceEquals(instance.store, original))
|
|
{
|
|
instance.Stop();
|
|
}
|
|
}
|
|
|
|
private void Stop()
|
|
{
|
|
tokenSource?.Cancel();
|
|
tokenSource?.Dispose();
|
|
tokenSource = null;
|
|
}
|
|
|
|
private async void UpdateUserDataValue(CancellationToken token)
|
|
{
|
|
try
|
|
{
|
|
while (!token.IsCancellationRequested)
|
|
{
|
|
SyncData();
|
|
await Task.Delay(40000);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogError("KV save schedule failed: " + ex.GetType().Name);
|
|
}
|
|
}
|
|
|
|
private void SyncData()
|
|
{
|
|
var original = store;
|
|
if (original != null && original.IsCurrent)
|
|
{
|
|
ObserveSync(original.SyncDataAsync());
|
|
}
|
|
}
|
|
|
|
private static async void ObserveSync(Task<PlayerKVFlushResult> task)
|
|
{
|
|
try
|
|
{
|
|
var result = await task;
|
|
if (result.TransportError != PlayerKVError.None || result.Blocked != 0 || result.Unknown != 0)
|
|
{
|
|
Debug.LogError("KV ordinary save failed: " + result.TransportError);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogError("KV ordinary save failed: " + ex.GetType().Name);
|
|
}
|
|
}
|
|
|
|
private void OnApplicationPause(bool paused)
|
|
{
|
|
if (paused)
|
|
{
|
|
Stop();
|
|
SyncData();
|
|
}
|
|
else
|
|
{
|
|
tokenSource = new CancellationTokenSource();
|
|
UpdateUserDataValue(tokenSource.Token);
|
|
}
|
|
}
|
|
|
|
private void OnApplicationQuit()
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
Stop();
|
|
SyncData();
|
|
store = null;
|
|
if (ReferenceEquals(instance, this))
|
|
{
|
|
instance = null;
|
|
}
|
|
}
|
|
|
|
internal static Task<PlayerKVFlushResult> SyncKVAsync(PlayerKVGameSessionHandle handle,
|
|
CancellationToken waitToken = default)
|
|
{
|
|
if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync))
|
|
{
|
|
return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Cancelled,
|
|
handle == null ? PlayerKVSyncStatus.NotLoaded : handle.Status));
|
|
}
|
|
if (handle == null)
|
|
{
|
|
return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Validation, PlayerKVSyncStatus.NotLoaded));
|
|
}
|
|
return handle.SyncDataAsync(waitToken);
|
|
}
|
|
|
|
internal static PlayerKVKeyReadResult ReadKV(PlayerKVGameSessionHandle handle, string key)
|
|
{
|
|
if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.ReadLocal))
|
|
{
|
|
return new PlayerKVKeyReadResult(PlayerKVKeyReadError.LoadGuardActive, handle);
|
|
}
|
|
if (handle == null || !KVSnapshot.ValidKey(key))
|
|
{
|
|
return new PlayerKVKeyReadResult(PlayerKVKeyReadError.InvalidInput, handle);
|
|
}
|
|
var read = handle.ReadLocalSnapshot();
|
|
if (!read.Success)
|
|
{
|
|
return new PlayerKVKeyReadResult(read.Error == PlayerKVLocalReadError.StaleOrClosing
|
|
? PlayerKVKeyReadError.StaleOrClosing : PlayerKVKeyReadError.NotReady, handle);
|
|
}
|
|
var found = read.Data.TryGetValue(key, out var value);
|
|
return new PlayerKVKeyReadResult(PlayerKVKeyReadError.None, handle, found, value);
|
|
}
|
|
|
|
internal static PlayerKVEditResult WriteKV(PlayerKVGameSessionHandle handle,
|
|
string key, string value, bool remoteStore = true)
|
|
{
|
|
if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Update))
|
|
{
|
|
return new PlayerKVEditResult(new PlayerKVStateResult(PlayerKVChangeError.Blocked));
|
|
}
|
|
if (handle == null)
|
|
{
|
|
return new PlayerKVEditResult(new PlayerKVStateResult(PlayerKVChangeError.Validation));
|
|
}
|
|
return handle.Update(key, value, remoteStore, ZZTimeHelper.UtcNow().Ticks);
|
|
}
|
|
|
|
internal static async Task<bool> SyncDataImmidiate(PlayerKVGameSessionHandle handle, string key, string value)
|
|
{
|
|
var success = false;
|
|
if (!PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Immediate) && handle != null &&
|
|
KVSnapshot.ValidKey(key) && value != null)
|
|
{
|
|
success = await handle.SyncDataImmidiate(key, value);
|
|
}
|
|
if (!success)
|
|
{
|
|
UnityEngine.Debug.LogError("[KVMgr::SyncDataImmidiate] Save failed.");
|
|
}
|
|
return success;
|
|
}
|
|
|
|
internal static async Task<bool> SyncDataImmidiate(PlayerKVGameSessionHandle handle,
|
|
IReadOnlyDictionary<string, string> values)
|
|
{
|
|
var success = false;
|
|
if (!PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Immediate) && handle != null && values != null && values.Count > 0)
|
|
{
|
|
success = await handle.SyncDataImmidiate(values);
|
|
}
|
|
if (!success)
|
|
{
|
|
UnityEngine.Debug.LogError("[KVMgr::SyncDataImmidiate] Save failed.");
|
|
}
|
|
return success;
|
|
}
|
|
|
|
internal static Task<PlayerKVFlushResult> FlushKVAsync(PlayerKVGameSessionHandle handle,
|
|
CancellationToken waitToken = default)
|
|
{
|
|
if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync))
|
|
{
|
|
return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Cancelled,
|
|
handle == null ? PlayerKVSyncStatus.NotLoaded : handle.Status));
|
|
}
|
|
if (handle == null)
|
|
{
|
|
return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Validation, PlayerKVSyncStatus.NotLoaded));
|
|
}
|
|
return handle.FlushAsync(waitToken);
|
|
}
|
|
|
|
internal static Task<PlayerKVTicketResult> WaitForKVTicketAsync(PlayerKVGameSessionHandle handle,
|
|
PlayerKVSyncTicket ticket, CancellationToken waitToken = default)
|
|
{
|
|
if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync))
|
|
{
|
|
return Task.FromResult(new PlayerKVTicketResult(PlayerKVTicketStatus.Blocked, PlayerKVError.Cancelled,
|
|
handle == null ? PlayerKVSyncStatus.NotLoaded : handle.Status));
|
|
}
|
|
if (handle == null)
|
|
{
|
|
return Task.FromResult(new PlayerKVTicketResult(PlayerKVTicketStatus.Blocked, PlayerKVError.Validation, PlayerKVSyncStatus.NotLoaded));
|
|
}
|
|
return handle.WaitForTicketAsync(ticket, waitToken);
|
|
}
|
|
}
|