diff --git a/SVSim.EmulatedEntrypoint/Controllers/SpotCardExchangeController.cs b/SVSim.EmulatedEntrypoint/Controllers/SpotCardExchangeController.cs index d5d8ec9..c5be16e 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/SpotCardExchangeController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/SpotCardExchangeController.cs @@ -4,6 +4,7 @@ using SVSim.Database; using SVSim.Database.Enums; using SVSim.Database.Models; using SVSim.Database.Services; +using SVSim.Database.Services.Inventory; using SVSim.EmulatedEntrypoint.Models.Dtos; using SVSim.EmulatedEntrypoint.Models.Dtos.Requests; using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.SpotCardExchange; @@ -14,8 +15,7 @@ namespace SVSim.EmulatedEntrypoint.Controllers; /// /// /spot_card_exchange/* — trade spot points for individual cards from the rotating exchange /// pool. Spot points are earned from battles/missions (not implemented here — earners live in -/// battle/mission finish reward emitters via + -/// ). +/// battle/mission finish reward emitters via ). /// [Route("spot_card_exchange")] public class SpotCardExchangeController : SVSimController @@ -28,16 +28,14 @@ public class SpotCardExchangeController : SVSimController private const int PreReleaseLimit = 2; private readonly SVSimDbContext _db; - private readonly RewardGrantService _rewards; + private readonly IInventoryService _inv; private readonly TimeProvider _time; - private readonly ICurrencySpendService _spend; - public SpotCardExchangeController(SVSimDbContext db, RewardGrantService rewards, TimeProvider time, ICurrencySpendService spend) + public SpotCardExchangeController(SVSimDbContext db, IInventoryService inv, TimeProvider time) { _db = db; - _rewards = rewards; + _inv = inv; _time = time; - _spend = spend; } [HttpPost("top")] @@ -126,14 +124,14 @@ public class SpotCardExchangeController : SVSimController return BadRequest(new { error = "pre_release_limit_reached" }); } - var viewer = await LoadViewerGraphAsync(viewerId); + await using var tx = await _inv.BeginAsync(viewerId); var rewardList = new List(); // Debit spot points. Client-supplied exchange_point isn't authoritative — server uses // catalog price. Mirroring the build_deck/sleeve convention: post-state currency entry // first, then grants. - var spotRes = await _spend.TrySpendAsync(viewer, SpendCurrency.SpotPoint, entry.ExchangePoint); + var spotRes = await tx.TrySpendAsync(SpendCurrency.SpotPoint, entry.ExchangePoint); if (!spotRes.Success) return BadRequest(new { error = "insufficient_spot_points" }); rewardList.Add(new RewardListEntry @@ -143,8 +141,8 @@ public class SpotCardExchangeController : SVSimController RewardNum = checked((int)spotRes.PostStateTotal), }); - // Grant the card itself via the existing card dispatcher (handles cosmetic cascade). - var granted = await _rewards.ApplyAsync(viewer, UserGoodsType.Card, entry.Id, 1); + // Grant the card itself via the inventory tx (handles cosmetic cascade). + var granted = await tx.GrantAsync(UserGoodsType.Card, entry.Id, 1); foreach (var g in granted) { rewardList.Add(new RewardListEntry @@ -163,7 +161,7 @@ public class SpotCardExchangeController : SVSimController ExchangedAt = _time.GetUtcNow().UtcDateTime, }); - await _db.SaveChangesAsync(); + await tx.CommitAsync(); return new SpotCardExchangeResponse { RewardList = rewardList }; } @@ -182,14 +180,4 @@ public class SpotCardExchangeController : SVSimController return 0; } - private Task LoadViewerGraphAsync(long viewerId) => _db.Viewers - .Include(v => v.Cards).ThenInclude(c => c.Card) - .Include(v => v.Sleeves) - .Include(v => v.Emblems) - .Include(v => v.LeaderSkins) - .Include(v => v.Degrees) - .Include(v => v.MyPageBackgrounds) - .Include(v => v.Items).ThenInclude(i => i.Item) - .AsSplitQuery() - .FirstAsync(v => v.Id == viewerId); }