neon-sprawl/server/NeonSprawl.Server/Game/AbilityInput/InMemoryPlayerHotbarLoadout...

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();
}
}