diff --git a/SVSim.EmulatedEntrypoint/Controllers/AchievementController.cs b/SVSim.EmulatedEntrypoint/Controllers/AchievementController.cs index 8c186b7..e345258 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/AchievementController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/AchievementController.cs @@ -2,9 +2,8 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using SVSim.Database; using SVSim.Database.Enums; -using SVSim.Database.Models; using SVSim.Database.Repositories.Mission; -using SVSim.Database.Services; +using SVSim.Database.Services.Inventory; using SVSim.EmulatedEntrypoint.Models.Dtos.Achievement; using SVSim.EmulatedEntrypoint.Services; @@ -22,20 +21,20 @@ public class AchievementController : SVSimController private readonly IMissionCatalogRepository _catalog; private readonly IViewerMissionStateService _state; private readonly IMissionAssembler _assembler; - private readonly RewardGrantService _grantService; + private readonly IInventoryService _inv; public AchievementController( SVSimDbContext db, IMissionCatalogRepository catalog, IViewerMissionStateService state, IMissionAssembler assembler, - RewardGrantService grantService) + IInventoryService inv) { _db = db; _catalog = catalog; _state = state; _assembler = assembler; - _grantService = grantService; + _inv = inv; } [HttpPost("receive_reward")] @@ -44,21 +43,15 @@ public class AchievementController : SVSimController { if (!TryGetViewerId(out long viewerId)) return Unauthorized(); - // Load viewer with all the collections RewardGrantService may need to mutate. - var viewer = await _db.Viewers - .Include(v => v.MissionData) - .Include(v => v.Currency) - .Include(v => v.Cards) - .Include(v => v.Items) - .Include(v => v.Sleeves) - .Include(v => v.Emblems) - .Include(v => v.Degrees) - .Include(v => v.LeaderSkins) - .Include(v => v.MyPageBackgrounds) - .AsSplitQuery() - .FirstAsync(v => v.Id == viewerId, ct); + // EnsureCurrentAsync needs a viewer id — use a lightweight pre-check load then + // materialize state before opening the inventory tx. + var viewerIdCheck = await _db.Viewers + .Where(v => v.Id == viewerId) + .Select(v => v.Id) + .FirstOrDefaultAsync(ct); + if (viewerIdCheck == 0) return Unauthorized(); - await _state.EnsureCurrentAsync(viewer.Id, ct); + await _state.EnsureCurrentAsync(viewerId, ct); await _db.SaveChangesAsync(ct); // Re-read viewer's achievement for this type after state-service materialization. @@ -75,9 +68,10 @@ public class AchievementController : SVSimController return Ok(new { result_code = FailureResultCode }); } - // Grant via the canonical RewardGrantService primitive. - var granted = await _grantService.ApplyAsync( - viewer, + // Open inventory tx and grant via InventoryService. + await using var tx = await _inv.BeginAsync(viewerId, ct); + + var granted = await tx.GrantAsync( (UserGoodsType)catalogRow.RewardType, catalogRow.RewardDetailId, catalogRow.RewardNumber, @@ -99,9 +93,9 @@ public class AchievementController : SVSimController } ach.NowAchievedLevel = request.Level; - await _db.SaveChangesAsync(ct); + await tx.CommitAsync(ct); - var dto = await _assembler.BuildAsync(viewer, ct); + var dto = await _assembler.BuildAsync(tx.Viewer, ct); var resp = new AchievementReceiveRewardResponse { UserMissionList = dto.UserMissionList,