feat(bp): IBattlePassService skeleton + level-curve method + DI

This commit is contained in:
gamer147
2026-05-26 22:49:30 -04:00
parent 1420c60486
commit 9043e20646
7 changed files with 96 additions and 3 deletions

View File

@@ -3,13 +3,18 @@ using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
/// <summary>
/// One entry under <c>/load/index.battle_pass_level_info</c>. Per memory
/// project_wire_key_serialization, wire ints are strings here — client parses them via .ToInt().
/// </summary>
[MessagePackObject]
public class BattlePassLevel
{
[JsonPropertyName("level")]
[Key("level")]
public int Level { get; set; }
public string Level { get; set; } = "";
[JsonPropertyName("required_point")]
[Key("required_point")]
public int RequiredPoints { get; set; }
}
public string RequiredPoint { get; set; } = "";
}

View File

@@ -83,6 +83,12 @@ public class Program
builder.Services.AddScoped<PackOpenService>();
builder.Services.AddScoped<ICardAcquisitionService, CardAcquisitionService>();
builder.Services.AddScoped<RewardGrantService>();
builder.Services.AddScoped<SVSim.Database.Repositories.BattlePass.IBattlePassRepository,
SVSim.Database.Repositories.BattlePass.BattlePassRepository>();
builder.Services.AddScoped<SVSim.Database.Repositories.BattlePass.IViewerBattlePassRepository,
SVSim.Database.Repositories.BattlePass.ViewerBattlePassRepository>();
builder.Services.AddScoped<IBattlePassService, BattlePassService>();
builder.Services.AddSingleton<TimeProvider>(TimeProvider.System);
builder.Services.AddScoped<IStoryMasterRepository, StoryMasterRepository>();
builder.Services.AddScoped<IViewerStoryProgressRepository, ViewerStoryProgressRepository>();
builder.Services.AddScoped<IStoryService, StoryService>();

View File

@@ -0,0 +1,14 @@
using SVSim.Database.Services;
namespace SVSim.EmulatedEntrypoint.Services;
/// <summary>
/// Result of <see cref="IBattlePassService.BuyPremiumAsync"/>. <c>AchievedRewards</c> = the
/// delta that was just granted (goes into <c>achieved_info.battle_pass_reward_list</c>);
/// <c>PostStateTotals</c> = post-state totals for affected goods (goes into <c>reward_list</c>),
/// including the crystal deduction per memory project_wire_reward_list_post_state.
/// </summary>
public sealed record BattlePassBuyOutcome(
int ResultCode,
IReadOnlyList<GrantedReward> AchievedRewards,
IReadOnlyList<GrantedReward> PostStateTotals);

View File

@@ -0,0 +1,17 @@
using SVSim.Database.Services;
namespace SVSim.EmulatedEntrypoint.Services;
/// <summary>
/// Result of <see cref="IBattlePassService.AddPointsAsync"/>. Future point-source endpoints
/// (mission/retire, battle finish handlers) translate this into the embedded
/// <c>battle_pass_gauge_info</c> block on their response.
/// </summary>
public sealed record BattlePassPointGrant(
int BeforePoint,
int BeforeLevel,
int AfterPoint,
int AfterLevel,
int PointAdd,
BattlePassPointSource Source,
IReadOnlyList<GrantedReward> NewlyClaimed);

View File

@@ -0,0 +1,12 @@
namespace SVSim.EmulatedEntrypoint.Services;
/// <summary>
/// Which categorized field on <c>battle_pass_gauge_info</c> a point grant feeds. Mirrors the
/// breakdown shown by <c>BattlePassResultPanel</c> after a win.
/// </summary>
public enum BattlePassPointSource
{
BattleResult,
DailyMission,
BattlePassMission,
}

View File

@@ -0,0 +1,28 @@
using System.Globalization;
using SVSim.Database.Repositories.BattlePass;
using SVSim.EmulatedEntrypoint.Models.Dtos;
namespace SVSim.EmulatedEntrypoint.Services;
public sealed class BattlePassService : IBattlePassService
{
private readonly IBattlePassRepository _bp;
public BattlePassService(IBattlePassRepository bp)
{
_bp = bp;
}
public async Task<IReadOnlyDictionary<string, BattlePassLevel>?> GetLevelCurveAsync(CancellationToken ct)
{
var rows = await _bp.GetLevelCurveAsync(ct);
if (rows.Count == 0) return null;
return rows.ToDictionary(
r => r.Level.ToString(CultureInfo.InvariantCulture),
r => new BattlePassLevel
{
Level = r.Level.ToString(CultureInfo.InvariantCulture),
RequiredPoint = r.RequiredPoint.ToString(CultureInfo.InvariantCulture),
});
}
}

View File

@@ -0,0 +1,11 @@
using SVSim.EmulatedEntrypoint.Models.Dtos;
namespace SVSim.EmulatedEntrypoint.Services;
public interface IBattlePassService
{
/// <summary>Global level curve as wire-string dictionary; null if no levels seeded.</summary>
Task<IReadOnlyDictionary<string, BattlePassLevel>?> GetLevelCurveAsync(CancellationToken ct);
// The Info / ItemList / Buy / AddPoints methods are added in later tasks (11, 12, 13, 14).
}