refactor(mission): migrate MissionProgressService + MissionAssembler to IGameCalendarService
Swaps 6 JstPeriod.* callsites in mission code to IGameCalendarService. Also drops the manual `jstNow = now.ToOffset(+9).AddHours(-2)` shift in MissionAssembler — BP monthly missions now key off UTC calendar month, and the start/end wire timestamps become UTC-midnight month boundaries. This matches the plan's all-UTC discipline; wire fidelity for BP monthlies is not shipped yet. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -9,15 +9,18 @@ public sealed class MissionAssembler : IMissionAssembler
|
||||
private readonly IMissionCatalogRepository _catalog;
|
||||
private readonly IViewerMissionRepository _viewerRepo;
|
||||
private readonly TimeProvider _time;
|
||||
private readonly IGameCalendarService _calendar;
|
||||
|
||||
public MissionAssembler(
|
||||
IMissionCatalogRepository catalog,
|
||||
IViewerMissionRepository viewerRepo,
|
||||
TimeProvider time)
|
||||
TimeProvider time,
|
||||
IGameCalendarService calendar)
|
||||
{
|
||||
_catalog = catalog;
|
||||
_viewerRepo = viewerRepo;
|
||||
_time = time;
|
||||
_calendar = calendar;
|
||||
}
|
||||
|
||||
public async Task<MissionInfoDataDto> BuildAsync(Viewer viewer, CancellationToken ct = default)
|
||||
@@ -54,15 +57,14 @@ public sealed class MissionAssembler : IMissionAssembler
|
||||
if (c.EventType is not null) counterEventKeys.Add(c.EventType);
|
||||
}
|
||||
|
||||
// BP monthly missions for current JST month.
|
||||
var jstNow = now.ToOffset(TimeSpan.FromHours(9)).AddHours(-2);
|
||||
var monthlyMissions = await _catalog.GetMonthlyMissionsAsync(jstNow.Year, jstNow.Month, ct);
|
||||
// BP monthly missions for the current calendar month (UTC).
|
||||
var monthlyMissions = await _catalog.GetMonthlyMissionsAsync(now.Year, now.Month, ct);
|
||||
foreach (var mm in monthlyMissions)
|
||||
{
|
||||
if (mm.EventType is not null) counterEventKeys.Add(mm.EventType);
|
||||
}
|
||||
|
||||
var periods = new[] { JstPeriod.DayKey(now), JstPeriod.WeekKey(now), JstPeriod.MonthKey(now), JstPeriod.AllTime };
|
||||
var periods = _calendar.AllPeriods(now);
|
||||
var counters = counterEventKeys.Count == 0
|
||||
? new List<ViewerEventCounter>()
|
||||
: await _viewerRepo.GetCountersAsync(viewer.Id, counterEventKeys.ToList(), periods, ct);
|
||||
@@ -78,7 +80,7 @@ public sealed class MissionAssembler : IMissionAssembler
|
||||
int total = 0;
|
||||
if (cat.EventType is not null)
|
||||
{
|
||||
string period = cat.LotType == 6 ? JstPeriod.DayKey(now) : JstPeriod.WeekKey(now);
|
||||
string period = cat.LotType == 6 ? _calendar.DayKey(now) : _calendar.WeekKey(now);
|
||||
total = GetCounter(cat.EventType, period);
|
||||
}
|
||||
dto.UserMissionList.Add(new UserMissionDto
|
||||
@@ -105,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, JstPeriod.AllTime);
|
||||
int total = catalog.EventType is null ? 0 : GetCounter(catalog.EventType, GameCalendarService.AllTime);
|
||||
int maxLevel = maxLevelByType.TryGetValue(a.AchievementType, out var ml) ? ml : a.Level;
|
||||
dto.UserAchievementList.Add(new UserAchievementDto
|
||||
{
|
||||
@@ -142,7 +144,7 @@ public sealed class MissionAssembler : IMissionAssembler
|
||||
// BP monthly missions block — omit when no rows for current month.
|
||||
if (monthlyMissions.Count > 0)
|
||||
{
|
||||
var startUtc = new DateTimeOffset(jstNow.Year, jstNow.Month, 1, 2, 0, 0, TimeSpan.FromHours(9));
|
||||
var startUtc = new DateTimeOffset(now.Year, now.Month, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
var endUtc = startUtc.AddMonths(1).AddSeconds(-1);
|
||||
dto.BattlePassMonthlyMission = new BPMonthlyMissionsDto
|
||||
{
|
||||
@@ -151,7 +153,7 @@ public sealed class MissionAssembler : IMissionAssembler
|
||||
MissionList = monthlyMissions.Select(mm =>
|
||||
{
|
||||
int done = mm.EventType is null ? 0
|
||||
: GetCounter(mm.EventType, JstPeriod.MonthKey(now));
|
||||
: GetCounter(mm.EventType, _calendar.MonthKey(now));
|
||||
var entry = new BPMonthlyMissionDto
|
||||
{
|
||||
Name = mm.Name,
|
||||
|
||||
@@ -9,24 +9,27 @@ public sealed class MissionProgressService : IMissionProgressService
|
||||
private readonly IMissionCatalogRepository _catalog;
|
||||
private readonly IViewerMissionRepository _viewerRepo;
|
||||
private readonly TimeProvider _time;
|
||||
private readonly IGameCalendarService _calendar;
|
||||
|
||||
public MissionProgressService(
|
||||
SVSimDbContext db,
|
||||
IMissionCatalogRepository catalog,
|
||||
IViewerMissionRepository viewerRepo,
|
||||
TimeProvider time)
|
||||
TimeProvider time,
|
||||
IGameCalendarService calendar)
|
||||
{
|
||||
_db = db;
|
||||
_catalog = catalog;
|
||||
_viewerRepo = viewerRepo;
|
||||
_time = time;
|
||||
_calendar = calendar;
|
||||
}
|
||||
|
||||
public async Task RecordEventAsync(long viewerId, IReadOnlyList<string> eventKeys, int delta = 1, CancellationToken ct = default)
|
||||
{
|
||||
if (eventKeys.Count == 0) return;
|
||||
var now = _time.GetUtcNow();
|
||||
var periods = JstPeriod.AllPeriods(now);
|
||||
var periods = _calendar.AllPeriods(now);
|
||||
|
||||
// 1. Increment counters for every (key, period).
|
||||
foreach (var key in eventKeys)
|
||||
@@ -50,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, JstPeriod.AllTime, ct);
|
||||
var count = await _viewerRepo.GetCounterAsync(viewerId, atLevel.EventType, GameCalendarService.AllTime, ct);
|
||||
if (count >= atLevel.RequireNumber && viewerRow.AchievementStatus == 0)
|
||||
{
|
||||
viewerRow.AchievementStatus = 1;
|
||||
|
||||
Reference in New Issue
Block a user