79 lines
2.5 KiB
C#
79 lines
2.5 KiB
C#
using System.Collections.Concurrent;
|
|
|
|
namespace NeonSprawl.Server.Game.Rewards;
|
|
|
|
/// <summary>Thread-safe in-memory reward delivery records (NEO-126).</summary>
|
|
public sealed class InMemoryRewardDeliveryStore : IRewardDeliveryStore
|
|
{
|
|
private readonly ConcurrentDictionary<string, RewardDeliveryEvent> eventsByKey = new(StringComparer.Ordinal);
|
|
|
|
private readonly ConcurrentDictionary<string, object> keyLocks = new(StringComparer.Ordinal);
|
|
|
|
/// <inheritdoc />
|
|
public bool TryRecord(RewardDeliveryEvent deliveryEvent)
|
|
{
|
|
var key = RewardDeliveryIds.MakeStoreKey(deliveryEvent);
|
|
if (key.Length == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
lock (keyLocks.GetOrAdd(key, _ => new object()))
|
|
{
|
|
if (eventsByKey.ContainsKey(key))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
eventsByKey[key] = deliveryEvent with
|
|
{
|
|
GrantedItems = [..deliveryEvent.GrantedItems],
|
|
GrantedSkillXp = [..deliveryEvent.GrantedSkillXp],
|
|
GrantedReputation = [..deliveryEvent.GrantedReputation],
|
|
};
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public bool TryGet(string playerId, string questId, out RewardDeliveryEvent deliveryEvent) =>
|
|
TryGet(playerId, RewardDeliverySourceKinds.QuestCompletion, questId, out deliveryEvent);
|
|
|
|
/// <inheritdoc />
|
|
public bool TryGet(string playerId, string sourceKind, string sourceId, out RewardDeliveryEvent deliveryEvent)
|
|
{
|
|
deliveryEvent = default;
|
|
var key = RewardDeliveryIds.MakeStoreKey(playerId, sourceKind, sourceId);
|
|
if (key.Length == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
lock (keyLocks.GetOrAdd(key, _ => new object()))
|
|
{
|
|
return eventsByKey.TryGetValue(key, out deliveryEvent);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public bool TryClear(string playerId, string questId) =>
|
|
TryClear(playerId, RewardDeliverySourceKinds.QuestCompletion, questId);
|
|
|
|
/// <summary>Dev fixture only — removes one player+source delivery row (Bruno / test reset).</summary>
|
|
public bool TryClear(string playerId, string sourceKind, string sourceId)
|
|
{
|
|
var key = RewardDeliveryIds.MakeStoreKey(playerId, sourceKind, sourceId);
|
|
if (key.Length == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
lock (keyLocks.GetOrAdd(key, _ => new object()))
|
|
{
|
|
_ = eventsByKey.TryRemove(key, out _);
|
|
keyLocks.TryRemove(key, out _);
|
|
return true;
|
|
}
|
|
}
|
|
}
|