GrantIfDueAsync advances streak (1..15 cycle), grants the day's reward via inventory tx, returns wire-shape DailyLoginBonus. IsDue helper for MyPage. Also fixes GameConfigurationJsonbTests section-count (15→16) which was broken since Task 3 added the LoginBonus [ConfigSection] but the assertion wasn't updated.
69 lines
2.5 KiB
C#
69 lines
2.5 KiB
C#
using System.Globalization;
|
|
using SVSim.Database.Models;
|
|
using SVSim.Database.Models.Config;
|
|
using SVSim.Database.Services;
|
|
using SVSim.Database.Services.Inventory;
|
|
using SVSim.EmulatedEntrypoint.Models.Dtos;
|
|
|
|
namespace SVSim.EmulatedEntrypoint.Services;
|
|
|
|
public class LoginBonusService : ILoginBonusService
|
|
{
|
|
private readonly IGameConfigService _config;
|
|
private readonly TimeProvider _time;
|
|
|
|
public LoginBonusService(IGameConfigService config, TimeProvider time)
|
|
{
|
|
_config = config;
|
|
_time = time;
|
|
}
|
|
|
|
public bool IsDue(Viewer viewer)
|
|
{
|
|
if (viewer.LastLoginBonusClaimedAt is null) return true;
|
|
var now = _time.GetUtcNow();
|
|
var lastClaim = new DateTimeOffset(
|
|
DateTime.SpecifyKind(viewer.LastLoginBonusClaimedAt.Value, DateTimeKind.Utc));
|
|
return JstPeriod.DayKey(lastClaim) != JstPeriod.DayKey(now);
|
|
}
|
|
|
|
public async Task<DailyLoginBonus?> GrantIfDueAsync(IInventoryTransaction tx, CancellationToken ct = default)
|
|
{
|
|
var viewer = tx.Viewer;
|
|
if (!IsDue(viewer)) return null;
|
|
|
|
var cfg = _config.Get<LoginBonusConfig>();
|
|
if (cfg.Normal.Count == 0) return null; // catalog misconfigured — nothing to grant
|
|
|
|
int newStreak = (viewer.LoginBonusStreak % cfg.Normal.Count) + 1;
|
|
var entry = cfg.Normal[newStreak - 1];
|
|
|
|
await tx.GrantAsync(entry.RewardType, entry.RewardDetailId, entry.RewardNumber, ct);
|
|
|
|
viewer.LoginBonusStreak = newStreak;
|
|
viewer.LastLoginBonusClaimedAt = _time.GetUtcNow().UtcDateTime;
|
|
|
|
return new DailyLoginBonus
|
|
{
|
|
Normal = new LoginBonusCampaign
|
|
{
|
|
Name = cfg.Name,
|
|
CampaignId = cfg.CampaignId.ToString(CultureInfo.InvariantCulture),
|
|
Img = cfg.Img,
|
|
NowCount = newStreak,
|
|
IsNextReward = true,
|
|
IsOneDayMultiRewards = false,
|
|
Rewards = cfg.Normal.Select(n => new LoginBonusReward
|
|
{
|
|
EffectId = n.EffectId.ToString(CultureInfo.InvariantCulture),
|
|
RewardType = ((int)n.RewardType).ToString(CultureInfo.InvariantCulture),
|
|
RewardDetailId = n.RewardDetailId.ToString(CultureInfo.InvariantCulture),
|
|
RewardNumber = n.RewardNumber.ToString(CultureInfo.InvariantCulture),
|
|
}).ToList(),
|
|
},
|
|
Total = null,
|
|
Campaign = new List<LoginBonusCampaign>(),
|
|
};
|
|
}
|
|
}
|