diff --git a/SVSim.EmulatedEntrypoint/Controllers/AdminController.cs b/SVSim.EmulatedEntrypoint/Controllers/AdminController.cs index bfbb9eab..dddb7413 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/AdminController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/AdminController.cs @@ -629,7 +629,7 @@ public class AdminController : SVSimController private static (string EventKey, string Period)? ResolveAchievementCounter(AchievementCatalogEntry catalog) { if (string.IsNullOrEmpty(catalog.EventType)) return null; - return (catalog.EventType!, GameCalendarService.AllTime); + return (catalog.EventType!, GameCalendarPeriods.AllTime); } /// diff --git a/SVSim.EmulatedEntrypoint/Controllers/ItemPurchaseController.cs b/SVSim.EmulatedEntrypoint/Controllers/ItemPurchaseController.cs index e354a312..beefcb46 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/ItemPurchaseController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/ItemPurchaseController.cs @@ -106,7 +106,7 @@ public class ItemPurchaseController : SVSimController return BadRequest(new { error = "unknown_purchase" }); var now = _time.GetUtcNow(); - var period = entry.IsMonthlyReset ? _calendar.MonthKey(now) : GameCalendarService.AllTime; + var period = entry.IsMonthlyReset ? _calendar.MonthKey(now) : GameCalendarPeriods.AllTime; var key = CounterKey(entry.Id); var counter = await _db.ViewerEventCounters @@ -160,11 +160,11 @@ public class ItemPurchaseController : SVSimController _ => "debit_type_not_supported", }; - private static string CounterKey(int purchaseId) => $"item_purchase:{purchaseId}"; + private static string CounterKey(int purchaseId) => MissionEventKeys.ItemPurchase(purchaseId); private static int CounterCount(List counters, ItemPurchaseCatalogEntry entry, string monthKey) { - var period = entry.IsMonthlyReset ? monthKey : GameCalendarService.AllTime; + var period = entry.IsMonthlyReset ? monthKey : GameCalendarPeriods.AllTime; return counters.FirstOrDefault(c => c.EventKey == CounterKey(entry.Id) && c.Period == period)?.Count ?? 0; } } diff --git a/SVSim.EmulatedEntrypoint/Services/GameCalendarService.cs b/SVSim.EmulatedEntrypoint/Services/GameCalendarService.cs index d7bff2ec..aa8184f8 100644 --- a/SVSim.EmulatedEntrypoint/Services/GameCalendarService.cs +++ b/SVSim.EmulatedEntrypoint/Services/GameCalendarService.cs @@ -32,10 +32,14 @@ public interface IGameCalendarService IReadOnlyList AllPeriods(DateTimeOffset when); } +public static class GameCalendarPeriods +{ + /// The lifetime bucket string — same constant regardless of reset boundary config. + public const string AllTime = "all-time"; +} + public class GameCalendarService : IGameCalendarService { - public const string AllTime = "all-time"; - private readonly IGameConfigService _config; public GameCalendarService(IGameConfigService config) @@ -73,7 +77,7 @@ public class GameCalendarService : IGameCalendarService public IReadOnlyList AllPeriods(DateTimeOffset when) => new[] { - DayKey(when), WeekKey(when), MonthKey(when), AllTime, + DayKey(when), WeekKey(when), MonthKey(when), GameCalendarPeriods.AllTime, }; private DateTime MostRecentBoundary(DateTime nowUtc) diff --git a/SVSim.EmulatedEntrypoint/Services/MissionAssembler.cs b/SVSim.EmulatedEntrypoint/Services/MissionAssembler.cs index d000b07b..7bb6102f 100644 --- a/SVSim.EmulatedEntrypoint/Services/MissionAssembler.cs +++ b/SVSim.EmulatedEntrypoint/Services/MissionAssembler.cs @@ -107,7 +107,7 @@ public sealed class MissionAssembler : IMissionAssembler foreach (var a in viewerAchievements.OrderBy(a => a.AchievementType)) { if (!achievementCatalogByKey.TryGetValue((a.AchievementType, a.Level), out var catalog)) continue; - int total = catalog.EventType is null ? 0 : GetCounter(catalog.EventType, GameCalendarService.AllTime); + int total = catalog.EventType is null ? 0 : GetCounter(catalog.EventType, GameCalendarPeriods.AllTime); int maxLevel = maxLevelByType.TryGetValue(a.AchievementType, out var ml) ? ml : a.Level; dto.UserAchievementList.Add(new UserAchievementDto { diff --git a/SVSim.EmulatedEntrypoint/Services/MissionProgressService.cs b/SVSim.EmulatedEntrypoint/Services/MissionProgressService.cs index 0d340f06..8e729c30 100644 --- a/SVSim.EmulatedEntrypoint/Services/MissionProgressService.cs +++ b/SVSim.EmulatedEntrypoint/Services/MissionProgressService.cs @@ -53,7 +53,7 @@ public sealed class MissionProgressService : IMissionProgressService var atLevel = catalogRows.FirstOrDefault(r => r.Level == viewerRow.Level); if (atLevel is null || atLevel.EventType is null) continue; - var count = await _viewerRepo.GetCounterAsync(viewerId, atLevel.EventType, GameCalendarService.AllTime, ct); + var count = await _viewerRepo.GetCounterAsync(viewerId, atLevel.EventType, GameCalendarPeriods.AllTime, ct); if (count >= atLevel.RequireNumber && viewerRow.AchievementStatus == 0) { viewerRow.AchievementStatus = 1; diff --git a/SVSim.UnitTests/Services/GameCalendarServiceTests.cs b/SVSim.UnitTests/Services/GameCalendarServiceTests.cs index b4c8a849..7430a2a1 100644 --- a/SVSim.UnitTests/Services/GameCalendarServiceTests.cs +++ b/SVSim.UnitTests/Services/GameCalendarServiceTests.cs @@ -122,7 +122,7 @@ public class GameCalendarServiceTests var svc = NewService(0); var periods = svc.AllPeriods(Utc(2026, 5, 27, 12, 0, 0)); Assert.That(periods, Is.EquivalentTo(new[] { - "day:2026-05-27", "week:2026-W22", "month:2026-05", GameCalendarService.AllTime, + "day:2026-05-27", "week:2026-W22", "month:2026-05", GameCalendarPeriods.AllTime, })); } }