using System; using System.Threading; using System.Threading.Tasks; namespace game.PlayerDataStorage { // A store belongs to one login. Callers retain this instance across awaits. public interface IPlayerSaveStore { bool IsCurrent { get; } PlayerSaveReadResult Read(string key); PlayerSaveWriteResult Write(string key, string value, bool remoteStore = true); Task WriteAndConfirmAsync(string key, string value, CancellationToken token = default); Task ConfirmAsync(PlayerSaveReceipt receipt, CancellationToken token = default); Task FlushAsync(CancellationToken token = default); } public sealed class PlayerSaveReadResult { public bool Success => Error == null; public bool? Found { get; } public string Value { get; } public string Error { get; } internal PlayerSaveReadResult(bool found, string value) { Found = found; Value = value; } internal PlayerSaveReadResult(string error) { Error = error ?? "ReadFailed"; } public string ValueOrThrow() { if (!Success) throw new InvalidOperationException("Player save read failed: " + Error); return Value; } } public sealed class PlayerSaveReceipt { internal readonly IPlayerSaveStore Store; internal readonly object Ticket; internal PlayerSaveReceipt(IPlayerSaveStore store, object ticket) { Store = store; Ticket = ticket; } } public sealed class PlayerSaveWriteResult { public bool Accepted => Error == null; public string Error { get; } public PlayerSaveReceipt Receipt { get; } internal PlayerSaveWriteResult(PlayerSaveReceipt receipt) { Receipt = receipt; } internal PlayerSaveWriteResult(string error) { Error = error ?? "WriteRejected"; } public void RequireAccepted() { if (!Accepted) throw new InvalidOperationException("Player save write rejected: " + Error); } } // Buffered and LocalOnly are deliberately different from cloud confirmation. public enum PlayerSaveStatus { Confirmed, Buffered, LocalOnly, Rejected, Superseded, Unknown, Cancelled } public sealed class PlayerSaveConfirmation { public PlayerSaveStatus Status { get; } public bool Confirmed => Status == PlayerSaveStatus.Confirmed; public string Error { get; } internal PlayerSaveConfirmation(PlayerSaveStatus status, string error = null) { Status = status; Error = error; } } }