refactor(inventory): delete old primitives after InventoryService cutover
Removed RewardGrantService, CurrencySpendService, ICurrencySpendService, ViewerEntitlements, IViewerEntitlements, CardAcquisitionService, ICardAcquisitionService, CardGrantResult and their tests (RewardGrantServiceTests, CurrencySpendServiceTests, CardAcquisitionServiceTests, ViewerEntitlementsTests). Removed four DI registrations from Program.cs. No caller references any deleted type; GrantedReward and EffectiveCosmetics were pre-moved to InventoryGrantTypes.cs in the prior commit. Build clean, 712/712 tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,101 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Database;
|
||||
using SVSim.Database.Enums;
|
||||
using SVSim.Database.Models;
|
||||
using SVSim.Database.Services;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Services;
|
||||
|
||||
public class CardAcquisitionService : ICardAcquisitionService
|
||||
{
|
||||
private readonly SVSimDbContext _db;
|
||||
private readonly RewardGrantService _rewards;
|
||||
|
||||
public CardAcquisitionService(SVSimDbContext db, RewardGrantService rewards)
|
||||
{
|
||||
_db = db;
|
||||
_rewards = rewards;
|
||||
}
|
||||
|
||||
public async Task<CardGrantResult> GrantManyAsync(long viewerId, IEnumerable<long> newCardIds)
|
||||
{
|
||||
var viewer = await LoadViewerWithGraph(viewerId);
|
||||
var rewardList = new List<RewardListEntry>();
|
||||
|
||||
// Bucket the input by id so multi-copy grants increment count once but cascade fires once.
|
||||
foreach (var grp in newCardIds.GroupBy(id => id))
|
||||
{
|
||||
int count = grp.Count();
|
||||
var granted = await _rewards.ApplyAsync(viewer, UserGoodsType.Card, grp.Key, count);
|
||||
foreach (var g in granted)
|
||||
{
|
||||
rewardList.Add(new RewardListEntry
|
||||
{
|
||||
RewardType = g.RewardType, RewardId = g.RewardId, RewardNum = g.RewardNum,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
return new CardGrantResult(rewardList);
|
||||
}
|
||||
|
||||
public async Task<CardGrantResult> BackfillCosmeticsAsync(long viewerId)
|
||||
{
|
||||
var viewer = await LoadViewerWithGraph(viewerId);
|
||||
var rewardList = new List<RewardListEntry>();
|
||||
|
||||
// Foil resolution: cascade rows live on non-foil ids. Apply the +1 convention.
|
||||
var lookupCardIds = viewer.Cards
|
||||
.Select(c => c.Card.IsFoil ? c.Card.Id - 1 : c.Card.Id)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
var cascade = await _db.CardCosmeticRewards
|
||||
.Where(r => lookupCardIds.Contains(r.CardId))
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var reward in cascade)
|
||||
{
|
||||
// Skip if the viewer already owns this cosmetic. ApplyAsync's cosmetic branches
|
||||
// unconditionally return a wire entry (top-level grant semantics), so we must
|
||||
// filter at the caller side to avoid emitting "+0 received" lines for cosmetics
|
||||
// the viewer has owned for ages.
|
||||
if (AlreadyOwnsCosmetic(viewer, reward.Type, reward.CosmeticId)) continue;
|
||||
|
||||
var goodsType = (UserGoodsType)(int)reward.Type;
|
||||
var granted = await _rewards.ApplyAsync(viewer, goodsType, reward.CosmeticId, 1);
|
||||
foreach (var g in granted)
|
||||
{
|
||||
rewardList.Add(new RewardListEntry
|
||||
{
|
||||
RewardType = g.RewardType, RewardId = g.RewardId, RewardNum = g.RewardNum,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
return new CardGrantResult(rewardList);
|
||||
}
|
||||
|
||||
private static bool AlreadyOwnsCosmetic(Viewer viewer, CosmeticType type, long id) => type switch
|
||||
{
|
||||
CosmeticType.Sleeve => viewer.Sleeves.Any(s => s.Id == id),
|
||||
CosmeticType.Emblem => viewer.Emblems.Any(e => e.Id == id),
|
||||
CosmeticType.Skin => viewer.LeaderSkins.Any(s => s.Id == id),
|
||||
CosmeticType.Degree => viewer.Degrees.Any(d => d.Id == id),
|
||||
CosmeticType.MyPageBG => viewer.MyPageBackgrounds.Any(b => b.Id == id),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
private Task<Viewer> LoadViewerWithGraph(long viewerId) => _db.Viewers
|
||||
.Include(v => v.Cards).ThenInclude(c => c.Card)
|
||||
.Include(v => v.LeaderSkins)
|
||||
.Include(v => v.Sleeves)
|
||||
.Include(v => v.Emblems)
|
||||
.Include(v => v.Degrees)
|
||||
.Include(v => v.MyPageBackgrounds)
|
||||
.AsSplitQuery()
|
||||
.FirstAsync(v => v.Id == viewerId);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Output of <see cref="ICardAcquisitionService.GrantAsync"/>. The RewardList is wire-shape:
|
||||
/// pass directly into a /pack/open or similar response's <c>data.reward_list</c> field.
|
||||
///
|
||||
/// In grant mode, contains one type=5 (Card) entry per distinct newCardId with post-state
|
||||
/// count, plus one entry per newly-granted cosmetic.
|
||||
/// In backfill mode, contains only cosmetic entries (no card-count entries).
|
||||
/// </summary>
|
||||
public record CardGrantResult(IReadOnlyList<RewardListEntry> RewardList);
|
||||
@@ -1,18 +0,0 @@
|
||||
namespace SVSim.EmulatedEntrypoint.Services;
|
||||
|
||||
public interface ICardAcquisitionService
|
||||
{
|
||||
/// <summary>
|
||||
/// Grant N cards + their CardCosmeticReward cascades in a single transaction.
|
||||
/// Used by /pack/open and any future endpoint that grants new cards in bulk.
|
||||
/// Returns wire-shape reward_list entries (post-state counts for cards, single-grant
|
||||
/// entries for any newly-added cosmetics).
|
||||
/// </summary>
|
||||
Task<CardGrantResult> GrantManyAsync(long viewerId, IEnumerable<long> newCardIds);
|
||||
|
||||
/// <summary>
|
||||
/// Scan all owned cards for missing CardCosmeticReward cosmetics; grant any not yet owned.
|
||||
/// Used by /load/index for retroactive cosmetic reconciliation. Card counts are NOT mutated.
|
||||
/// </summary>
|
||||
Task<CardGrantResult> BackfillCosmeticsAsync(long viewerId);
|
||||
}
|
||||
Reference in New Issue
Block a user