diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/BattlePassLevel.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/BattlePassLevel.cs
index 23a1c00..e878f43 100644
--- a/SVSim.EmulatedEntrypoint/Models/Dtos/BattlePassLevel.cs
+++ b/SVSim.EmulatedEntrypoint/Models/Dtos/BattlePassLevel.cs
@@ -3,13 +3,18 @@ using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
+///
+/// One entry under /load/index.battle_pass_level_info. Per memory
+/// project_wire_key_serialization, wire ints are strings here — client parses them via .ToInt().
+///
[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; }
-}
\ No newline at end of file
+ public string RequiredPoint { get; set; } = "";
+}
diff --git a/SVSim.EmulatedEntrypoint/Program.cs b/SVSim.EmulatedEntrypoint/Program.cs
index 6e6c187..8d06003 100644
--- a/SVSim.EmulatedEntrypoint/Program.cs
+++ b/SVSim.EmulatedEntrypoint/Program.cs
@@ -83,6 +83,12 @@ public class Program
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
+ builder.Services.AddScoped();
+ builder.Services.AddScoped();
+ builder.Services.AddScoped();
+ builder.Services.AddSingleton(TimeProvider.System);
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
diff --git a/SVSim.EmulatedEntrypoint/Services/BattlePassBuyOutcome.cs b/SVSim.EmulatedEntrypoint/Services/BattlePassBuyOutcome.cs
new file mode 100644
index 0000000..5d7060f
--- /dev/null
+++ b/SVSim.EmulatedEntrypoint/Services/BattlePassBuyOutcome.cs
@@ -0,0 +1,14 @@
+using SVSim.Database.Services;
+
+namespace SVSim.EmulatedEntrypoint.Services;
+
+///
+/// Result of . AchievedRewards = the
+/// delta that was just granted (goes into achieved_info.battle_pass_reward_list);
+/// PostStateTotals = post-state totals for affected goods (goes into reward_list),
+/// including the crystal deduction per memory project_wire_reward_list_post_state.
+///
+public sealed record BattlePassBuyOutcome(
+ int ResultCode,
+ IReadOnlyList AchievedRewards,
+ IReadOnlyList PostStateTotals);
diff --git a/SVSim.EmulatedEntrypoint/Services/BattlePassPointGrant.cs b/SVSim.EmulatedEntrypoint/Services/BattlePassPointGrant.cs
new file mode 100644
index 0000000..686d7ea
--- /dev/null
+++ b/SVSim.EmulatedEntrypoint/Services/BattlePassPointGrant.cs
@@ -0,0 +1,17 @@
+using SVSim.Database.Services;
+
+namespace SVSim.EmulatedEntrypoint.Services;
+
+///
+/// Result of . Future point-source endpoints
+/// (mission/retire, battle finish handlers) translate this into the embedded
+/// battle_pass_gauge_info block on their response.
+///
+public sealed record BattlePassPointGrant(
+ int BeforePoint,
+ int BeforeLevel,
+ int AfterPoint,
+ int AfterLevel,
+ int PointAdd,
+ BattlePassPointSource Source,
+ IReadOnlyList NewlyClaimed);
diff --git a/SVSim.EmulatedEntrypoint/Services/BattlePassPointSource.cs b/SVSim.EmulatedEntrypoint/Services/BattlePassPointSource.cs
new file mode 100644
index 0000000..9765cf1
--- /dev/null
+++ b/SVSim.EmulatedEntrypoint/Services/BattlePassPointSource.cs
@@ -0,0 +1,12 @@
+namespace SVSim.EmulatedEntrypoint.Services;
+
+///
+/// Which categorized field on battle_pass_gauge_info a point grant feeds. Mirrors the
+/// breakdown shown by BattlePassResultPanel after a win.
+///
+public enum BattlePassPointSource
+{
+ BattleResult,
+ DailyMission,
+ BattlePassMission,
+}
diff --git a/SVSim.EmulatedEntrypoint/Services/BattlePassService.cs b/SVSim.EmulatedEntrypoint/Services/BattlePassService.cs
new file mode 100644
index 0000000..061049e
--- /dev/null
+++ b/SVSim.EmulatedEntrypoint/Services/BattlePassService.cs
@@ -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?> 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),
+ });
+ }
+}
diff --git a/SVSim.EmulatedEntrypoint/Services/IBattlePassService.cs b/SVSim.EmulatedEntrypoint/Services/IBattlePassService.cs
new file mode 100644
index 0000000..5aa0637
--- /dev/null
+++ b/SVSim.EmulatedEntrypoint/Services/IBattlePassService.cs
@@ -0,0 +1,11 @@
+using SVSim.EmulatedEntrypoint.Models.Dtos;
+
+namespace SVSim.EmulatedEntrypoint.Services;
+
+public interface IBattlePassService
+{
+ /// Global level curve as wire-string dictionary; null if no levels seeded.
+ Task?> GetLevelCurveAsync(CancellationToken ct);
+
+ // The Info / ItemList / Buy / AddPoints methods are added in later tasks (11, 12, 13, 14).
+}