76 lines
2.4 KiB
C#
76 lines
2.4 KiB
C#
using System.Collections.Concurrent;
|
|
using Microsoft.Extensions.Options;
|
|
using NeonSprawl.Server.Game.PositionState;
|
|
|
|
namespace NeonSprawl.Server.Game.AbilityInput;
|
|
|
|
/// <summary>Thread-safe in-memory hotbar loadout store; seeds configured dev player with an empty loadout.</summary>
|
|
public sealed class InMemoryPlayerHotbarLoadoutStore(IOptions<GamePositionOptions> options) : IPlayerHotbarLoadoutStore
|
|
{
|
|
private readonly ConcurrentDictionary<string, ConcurrentDictionary<int, string>> byPlayer =
|
|
CreateInitialMap(options.Value);
|
|
|
|
private static ConcurrentDictionary<string, ConcurrentDictionary<int, string>> CreateInitialMap(GamePositionOptions o)
|
|
{
|
|
var id = NormalizePlayerId(o.DevPlayerId);
|
|
var map = new ConcurrentDictionary<string, ConcurrentDictionary<int, string>>(StringComparer.OrdinalIgnoreCase);
|
|
map[id] = new ConcurrentDictionary<int, string>();
|
|
return map;
|
|
}
|
|
|
|
public bool TryGetBindings(string playerId, out IReadOnlyDictionary<int, string> bindings)
|
|
{
|
|
var key = NormalizePlayerId(playerId);
|
|
if (key.Length == 0 || !byPlayer.TryGetValue(key, out var map))
|
|
{
|
|
bindings = EmptyBindings();
|
|
return false;
|
|
}
|
|
|
|
bindings = Clone(map);
|
|
return true;
|
|
}
|
|
|
|
public bool TryUpsertBindings(string playerId, IReadOnlyList<HotbarSlotBinding> updates, out IReadOnlyDictionary<int, string> bindings)
|
|
{
|
|
var key = NormalizePlayerId(playerId);
|
|
if (key.Length == 0 || !byPlayer.TryGetValue(key, out var map))
|
|
{
|
|
bindings = EmptyBindings();
|
|
return false;
|
|
}
|
|
|
|
foreach (var update in updates)
|
|
{
|
|
map[update.SlotIndex] = update.AbilityId;
|
|
}
|
|
|
|
bindings = Clone(map);
|
|
return true;
|
|
}
|
|
|
|
private static Dictionary<int, string> Clone(ConcurrentDictionary<int, string> source)
|
|
{
|
|
var copy = new Dictionary<int, string>(source.Count);
|
|
foreach (var kv in source)
|
|
{
|
|
copy[kv.Key] = kv.Value;
|
|
}
|
|
|
|
return copy;
|
|
}
|
|
|
|
private static Dictionary<int, string> EmptyBindings() => [];
|
|
|
|
private static string NormalizePlayerId(string? playerId)
|
|
{
|
|
var t = playerId?.Trim();
|
|
if (string.IsNullOrEmpty(t))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return t.ToLowerInvariant();
|
|
}
|
|
}
|