diff --git a/PlaytimeHistory.cs b/PlaytimeHistory.cs index 0f6e2e4..ac67b8d 100644 --- a/PlaytimeHistory.cs +++ b/PlaytimeHistory.cs @@ -23,7 +23,7 @@ namespace PlaytimeHistory; public class PlaytimeHistory : BasePlugin, IPluginConfig { public override string ModuleName => "PlaytimeHistory"; - public override string ModuleVersion => "0.2.0"; + public override string ModuleVersion => "0.2.1"; public override string ModuleAuthor => "astra"; public override string ModuleDescription => "Records playtime per session, team and alive/dead state"; diff --git a/Writer.cs b/Writer.cs index 1ac4df3..e27aff7 100644 --- a/Writer.cs +++ b/Writer.cs @@ -38,7 +38,9 @@ public sealed class Writer _logger = logger; } - public int Queued => _queue.Reader.Count; + // Kept here: a single-reader unbounded channel can't count itself (Reader.Count throws). + private int _queued; + public int Queued => Volatile.Read(ref _queued); public int Spooled => _spooled; public bool Migrated => Volatile.Read(ref _migrated); public bool Failing => Volatile.Read(ref _failing); @@ -48,7 +50,11 @@ public sealed class Writer public void Start() => _loop = Task.Run(RunAsync); // From the game thread. Never blocks. - public void Enqueue(Op op) => _queue.Writer.TryWrite(op); + public void Enqueue(Op op) + { + if (_queue.Writer.TryWrite(op)) + Interlocked.Increment(ref _queued); + } // On unload: sends what's queued, waiting up to `timeout`, then spools anything left. public void Drain(TimeSpan timeout) @@ -66,7 +72,10 @@ public sealed class Writer } } while (_queue.Reader.TryRead(out var op)) + { + Interlocked.Decrement(ref _queued); Spool(op); + } } private async Task RunAsync() @@ -87,7 +96,10 @@ public sealed class Writer } while (_queue.Reader.TryRead(out var op)) + { + Interlocked.Decrement(ref _queued); await HandleAsync(op, token); + } bool more; try