feat(pack): /pack/info filters spent free-pack children and emits campaign metadata
This commit is contained in:
@@ -92,10 +92,19 @@ public class PackController : SVSimController
|
||||
.Select(b => new { b.PackId, b.Points })
|
||||
.ToDictionaryAsync(x => x.PackId, x => x.Points);
|
||||
|
||||
// Per-viewer free-pack claim records, keyed by campaign id. Drives the
|
||||
// "drop the type_detail=10 child once today's quota is spent" filter in ToDto.
|
||||
// Plain projection — no owned-entity tracking needed (mirrors the items query above).
|
||||
var freeClaimsByCampaignId = await _db.Viewers
|
||||
.Where(v => v.Id == viewerId)
|
||||
.SelectMany(v => v.FreePackClaims)
|
||||
.Select(c => new { c.FreeGachaCampaignId, c.LastClaimedAt, c.ClaimCount })
|
||||
.ToDictionaryAsync(x => x.FreeGachaCampaignId, x => (x.LastClaimedAt, x.ClaimCount));
|
||||
|
||||
return new PackInfoResponse
|
||||
{
|
||||
PackConfigList = packs
|
||||
.Select(p => ToDto(p, openCounts, ownedItemsByItemId, gachaPointBalancesByPackId))
|
||||
.Select(p => ToDto(p, openCounts, ownedItemsByItemId, gachaPointBalancesByPackId, freeClaimsByCampaignId))
|
||||
.ToList(),
|
||||
};
|
||||
}
|
||||
@@ -104,14 +113,31 @@ public class PackController : SVSimController
|
||||
PackConfigEntry p,
|
||||
IReadOnlyDictionary<int, ViewerPackOpenCount> openCounts,
|
||||
IReadOnlyDictionary<long, int> ownedItemsByItemId,
|
||||
IReadOnlyDictionary<int, int> gachaPointBalancesByPackId)
|
||||
IReadOnlyDictionary<int, int> gachaPointBalancesByPackId,
|
||||
IReadOnlyDictionary<int, (DateTime LastClaimedAt, int ClaimCount)> freeClaimsByCampaignId)
|
||||
{
|
||||
int openCount = openCounts.TryGetValue(p.Id, out var oc) ? oc.OpenCount : 0;
|
||||
|
||||
// Drop type_detail=10 (FREE_PACKS) children whose daily quota for THIS viewer is spent.
|
||||
// Mirrors prod behavior: post-claim /pack/info simply omits the free child from
|
||||
// child_gacha_info (verified in traffic_event_crate_free_pack.ndjson lines 28→32).
|
||||
// Today's claim count >= DailyFreeGachaCount and same UTC date => hide.
|
||||
var today = DateTime.UtcNow.Date;
|
||||
bool ChildAvailable(PackChildGachaEntry c)
|
||||
{
|
||||
if (c.TypeDetail != 10) return true;
|
||||
if (c.FreeGachaCampaignId is not int campaignId) return true;
|
||||
if (!freeClaimsByCampaignId.TryGetValue(campaignId, out var claim)) return true;
|
||||
if (claim.LastClaimedAt.Date != today) return true;
|
||||
int dailyCap = c.DailyFreeGachaCount > 0 ? c.DailyFreeGachaCount : 1;
|
||||
return claim.ClaimCount < dailyCap;
|
||||
}
|
||||
var visibleChildren = p.ChildGachas.Where(ChildAvailable).ToList();
|
||||
|
||||
// Ticket-only pack: every child is TICKET (4) or TICKET_MULTI (5). These are
|
||||
// gifted-currency packs (tutorial starter, throwback) that don't participate in
|
||||
// gacha-point accrual or exchange, even if GachaPointConfig is set in seed.
|
||||
bool isTicketOnly = p.ChildGachas.All(c => c.TypeDetail == 4 || c.TypeDetail == 5);
|
||||
bool isTicketOnly = visibleChildren.All(c => c.TypeDetail == 4 || c.TypeDetail == 5);
|
||||
|
||||
PackGachaPointDto? gachaPointDto = null;
|
||||
if (p.GachaPointConfig is not null && !isTicketOnly)
|
||||
@@ -145,7 +171,7 @@ public class PackController : SVSimController
|
||||
DialogTitle = b.DialogTitle,
|
||||
}).ToList(),
|
||||
GachaDetail = p.GachaDetail,
|
||||
ChildGachaInfo = p.ChildGachas.Select(c => new PackChildGachaDto
|
||||
ChildGachaInfo = visibleChildren.Select(c => new PackChildGachaDto
|
||||
{
|
||||
GachaId = c.GachaId,
|
||||
TypeDetail = c.TypeDetail,
|
||||
@@ -164,6 +190,14 @@ public class PackController : SVSimController
|
||||
: 0,
|
||||
IsDailySingle = c.IsDailySingle,
|
||||
OverrideIncreaseGachaPoint = c.OverrideIncreaseGachaPoint.ToString(CultureInfo.InvariantCulture),
|
||||
CampaignName = c.CampaignName,
|
||||
PurchaseLimitCount = c.PurchaseLimitCount > 0
|
||||
? c.PurchaseLimitCount.ToString(CultureInfo.InvariantCulture)
|
||||
: null,
|
||||
DailyFreeGachaCount = c.DailyFreeGachaCount > 0
|
||||
? c.DailyFreeGachaCount.ToString(CultureInfo.InvariantCulture)
|
||||
: null,
|
||||
FreeGachaCampaignId = c.FreeGachaCampaignId,
|
||||
}).ToList(),
|
||||
OpenCount = openCount,
|
||||
OpenCountLimit = p.OpenCountLimit,
|
||||
|
||||
Reference in New Issue
Block a user