From d68a85bbc54272273c6c5219a80ad2d0b9b6bc57 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Fri, 29 May 2026 14:23:50 -0400 Subject: [PATCH] refactor(battlepass): route premium-buy crystal spend through CurrencySpendService Co-Authored-By: Claude Sonnet 4.6 --- .../Services/BattlePassService.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/SVSim.EmulatedEntrypoint/Services/BattlePassService.cs b/SVSim.EmulatedEntrypoint/Services/BattlePassService.cs index 0a10e66..2a07fcc 100644 --- a/SVSim.EmulatedEntrypoint/Services/BattlePassService.cs +++ b/SVSim.EmulatedEntrypoint/Services/BattlePassService.cs @@ -23,19 +23,22 @@ public sealed class BattlePassService : IBattlePassService private readonly TimeProvider _time; private readonly SVSimDbContext _db; private readonly RewardGrantService _rewards; + private readonly ICurrencySpendService _spend; public BattlePassService( IBattlePassRepository bp, IViewerBattlePassRepository viewerBp, TimeProvider time, SVSimDbContext db, - RewardGrantService rewards) + RewardGrantService rewards, + ICurrencySpendService spend) { _bp = bp; _viewerBp = viewerBp; _time = time; _db = db; _rewards = rewards; + _spend = spend; } public async Task?> GetLevelCurveAsync(CancellationToken ct) @@ -166,13 +169,13 @@ public sealed class BattlePassService : IBattlePassService if (progress.IsPremium) return new BattlePassBuyOutcome(23, Array.Empty(), Array.Empty()); - if (viewer.Currency.Crystals < (ulong)season.PriceCrystal) + var spendResult = await _spend.TrySpendAsync(viewer, SpendCurrency.Crystal, season.PriceCrystal, ct); + if (!spendResult.Success) return new BattlePassBuyOutcome(22, Array.Empty(), Array.Empty()); // BeginTransactionAsync is a no-op on the SQLite in-memory test DB but is safe to call. await using var tx = await _db.Database.BeginTransactionAsync(ct); - viewer.Currency.Crystals -= (ulong)season.PriceCrystal; progress.IsPremium = true; // Retroactive grants: every premium reward at level <= current_level not already claimed. @@ -206,7 +209,7 @@ public sealed class BattlePassService : IBattlePassService // append the post-deduction total so the client gets the correct final balance. postState.RemoveAll(r => r.RewardType == (int)UserGoodsType.Crystal); postState.Add(new GrantedReward( - (int)UserGoodsType.Crystal, 0, (int)viewer.Currency.Crystals)); + (int)UserGoodsType.Crystal, 0, (int)spendResult.PostStateTotal)); return new BattlePassBuyOutcome(1, achieved, postState); }