using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.PositionState; namespace NeonSprawl.Server.Game.Quests; /// Maps GET /game/players/{{id}}/quest-progress (NEO-119). public static class QuestProgressApi { public const string StatusNotStarted = "not_started"; public const string StatusActive = "active"; public const string StatusCompleted = "completed"; public static WebApplication MapQuestProgressApi(this WebApplication app) { app.MapGet( "/game/players/{id}/quest-progress", (string id, IPositionStateStore positions, IQuestDefinitionRegistry questRegistry, IPlayerQuestStateStore progressStore, IPlayerInventoryStore inventoryStore, IItemDefinitionRegistry itemRegistry, TimeProvider timeProvider, ILogger? logger) => { var trimmedId = id.Trim(); if (trimmedId.Length == 0 || !positions.TryGetPosition(trimmedId, out _)) { return Results.NotFound(); } QuestObjectiveWiring.TryRefreshInventoryProgressForPlayer( trimmedId, questRegistry, progressStore, inventoryStore, itemRegistry, timeProvider, logger); return Results.Json(BuildSnapshot(trimmedId, questRegistry, progressStore)); }); return app; } internal static QuestProgressListResponse BuildSnapshot( string playerId, IQuestDefinitionRegistry questRegistry, IPlayerQuestStateStore progressStore) { var defs = questRegistry.GetDefinitionsInIdOrder(); var rows = new List(defs.Count); foreach (var def in defs) { rows.Add(MapQuestProgressRow(playerId, def.Id, progressStore)); } return new QuestProgressListResponse { PlayerId = playerId, Quests = rows, SchemaVersion = QuestProgressListResponse.CurrentSchemaVersion, }; } internal static QuestProgressRowJson MapQuestProgressRow( string playerId, string questId, IPlayerQuestStateStore progressStore) { if (!progressStore.TryGetProgress(playerId, questId, out var snapshot)) { return NotStartedRow(questId); } return MapQuestProgressRow(snapshot); } internal static QuestProgressRowJson MapQuestProgressRow(QuestStepState snapshot) { var counters = new Dictionary(snapshot.ObjectiveCounters, StringComparer.Ordinal); return snapshot.Status switch { QuestProgressStatus.Active => new QuestProgressRowJson { QuestId = snapshot.QuestId, Status = StatusActive, CurrentStepIndex = snapshot.CurrentStepIndex, ObjectiveCounters = counters, }, QuestProgressStatus.Completed => new QuestProgressRowJson { QuestId = snapshot.QuestId, Status = StatusCompleted, CurrentStepIndex = snapshot.CurrentStepIndex, ObjectiveCounters = counters, CompletedAt = snapshot.CompletedAt, }, _ => throw new InvalidOperationException($"Unknown quest progress status '{snapshot.Status}'."), }; } private static QuestProgressRowJson NotStartedRow(string questId) => new() { QuestId = questId, Status = StatusNotStarted, CurrentStepIndex = 0, ObjectiveCounters = new Dictionary(StringComparer.Ordinal), }; }