89 lines
2.5 KiB
C#
89 lines
2.5 KiB
C#
using System.Collections.Concurrent;
|
|
|
|
namespace NeonSprawl.Server.Game.Gathering;
|
|
|
|
/// <summary>Thread-safe in-memory node instance capacity; empty at startup — lazy rows only (NEO-61).</summary>
|
|
public sealed class InMemoryResourceNodeInstanceStore : IResourceNodeInstanceStore
|
|
{
|
|
private readonly ConcurrentDictionary<string, int> remainingById = new(StringComparer.Ordinal);
|
|
|
|
private readonly ConcurrentDictionary<string, object> idLocks = new(StringComparer.Ordinal);
|
|
|
|
/// <inheritdoc />
|
|
public bool TryGetRemainingGathers(string interactableId, out ResourceNodeInstanceSnapshot snapshot)
|
|
{
|
|
var key = ResourceNodeInstanceIds.Normalize(interactableId);
|
|
if (key.Length == 0)
|
|
{
|
|
snapshot = default;
|
|
return false;
|
|
}
|
|
|
|
lock (idLocks.GetOrAdd(key, _ => new object()))
|
|
{
|
|
if (!remainingById.TryGetValue(key, out var remaining))
|
|
{
|
|
snapshot = default;
|
|
return false;
|
|
}
|
|
|
|
snapshot = new ResourceNodeInstanceSnapshot(key, remaining);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public bool TryEnsureInitialized(string interactableId, int initialRemainingGathers)
|
|
{
|
|
var key = ResourceNodeInstanceIds.Normalize(interactableId);
|
|
if (key.Length == 0 || initialRemainingGathers < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
lock (idLocks.GetOrAdd(key, _ => new object()))
|
|
{
|
|
if (remainingById.ContainsKey(key))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
remainingById[key] = initialRemainingGathers;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public bool TryDecrementRemainingGathers(
|
|
string interactableId,
|
|
out int previousRemaining,
|
|
out int remainingGathers)
|
|
{
|
|
previousRemaining = 0;
|
|
remainingGathers = 0;
|
|
var key = ResourceNodeInstanceIds.Normalize(interactableId);
|
|
if (key.Length == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
lock (idLocks.GetOrAdd(key, _ => new object()))
|
|
{
|
|
if (!remainingById.TryGetValue(key, out var current) || current <= 0)
|
|
{
|
|
if (current == 0)
|
|
{
|
|
remainingGathers = 0;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
previousRemaining = current;
|
|
remainingGathers = current - 1;
|
|
remainingById[key] = remainingGathers;
|
|
return true;
|
|
}
|
|
}
|
|
}
|