using NeonSprawl.Server.Game.PositionState; namespace NeonSprawl.Server.Game.AbilityInput; /// GET /game/players/{{id}}/cooldown-snapshot (NEO-32). public static class CooldownSnapshotApi { public static WebApplication MapCooldownSnapshotApi(this WebApplication app) { app.MapGet( "/game/players/{id}/cooldown-snapshot", (string id, IPositionStateStore positions, IPlayerAbilityCooldownStore cooldowns, TimeProvider clock) => { if (!positions.TryGetPosition(id, out _)) { return Results.NotFound(); } return Results.Json(BuildSnapshot(id, cooldowns, clock)); }); return app; } internal static CooldownSnapshotResponse BuildSnapshot( string playerId, IPlayerAbilityCooldownStore cooldowns, TimeProvider clock) { var now = clock.GetUtcNow(); var slots = new List(HotbarLoadoutResponse.SlotCountV1); for (var i = 0; i < HotbarLoadoutResponse.SlotCountV1; i++) { DateTimeOffset? end = null; if (cooldowns.TryGetCooldownEndUtc(playerId, i, now, out var endUtc)) { end = endUtc; } slots.Add(new CooldownSlotSnapshotJson { SlotIndex = i, CooldownEndsAtUtc = end }); } return new CooldownSnapshotResponse { PlayerId = playerId, ServerTimeUtc = now, Slots = slots, }; } }