44 lines
1.8 KiB
C#
44 lines
1.8 KiB
C#
using System;
|
|
using System.Threading;
|
|
|
|
namespace game.PlayerDataStorage
|
|
{
|
|
internal enum PlayerKVGuardPoint { Compare, ReadLocal, Update, Immediate, Sync, Lifecycle, PrefsSave }
|
|
internal sealed class PlayerKVLoadSideEffectException : InvalidOperationException
|
|
{ internal PlayerKVLoadSideEffectException() : base("KV controlled load rejected a legacy side effect.") { } }
|
|
internal sealed class PlayerKVGameLoadGuard : IDisposable
|
|
{
|
|
static readonly object gate=new object();
|
|
static PlayerKVGameLoadGuard owner;
|
|
readonly int[] counts=new int[7];
|
|
int violations;
|
|
bool disposed;
|
|
private PlayerKVGameLoadGuard() { }
|
|
internal static bool TryEnter(out PlayerKVGameLoadGuard lease)
|
|
{
|
|
lock(gate)
|
|
{
|
|
lease=null; if(owner!=null) return false;
|
|
owner=lease=new PlayerKVGameLoadGuard(); return true;
|
|
}
|
|
}
|
|
internal bool IsCurrent { get { lock(gate) return !disposed && ReferenceEquals(owner,this); } }
|
|
internal int Violations => Volatile.Read(ref violations);
|
|
internal int Count(PlayerKVGuardPoint point) => Volatile.Read(ref counts[(int)point]);
|
|
internal static bool Reject(PlayerKVGuardPoint point)
|
|
{
|
|
lock(gate)
|
|
{
|
|
if(owner==null) return false;
|
|
Interlocked.Increment(ref owner.counts[(int)point]); Interlocked.Increment(ref owner.violations); return true;
|
|
}
|
|
}
|
|
internal static void RequireLegacyAllowed(PlayerKVGuardPoint point)
|
|
{ if(Reject(point)) throw new PlayerKVLoadSideEffectException(); }
|
|
public void Dispose()
|
|
{
|
|
lock(gate) { if(disposed) return; disposed=true; if(ReferenceEquals(owner,this)) owner=null; }
|
|
}
|
|
}
|
|
}
|