From 30b8af2d16e10d94df86e3a8773c7fe5ecbe1b56 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Fri, 12 Jun 2026 23:26:29 -0400 Subject: [PATCH] feat(pack): /pack/get_leader_skin_owned_status (empty per-class buckets) --- .../Controllers/PackController.cs | 14 ++++++++ .../PackGetLeaderSkinOwnedStatusRequest.cs | 13 +++++++ ...ackControllerLeaderSkinOwnedStatusTests.cs | 34 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Pack/PackGetLeaderSkinOwnedStatusRequest.cs create mode 100644 SVSim.UnitTests/Controllers/PackControllerLeaderSkinOwnedStatusTests.cs diff --git a/SVSim.EmulatedEntrypoint/Controllers/PackController.cs b/SVSim.EmulatedEntrypoint/Controllers/PackController.cs index ae5353b1..ef0efbb9 100644 --- a/SVSim.EmulatedEntrypoint/Controllers/PackController.cs +++ b/SVSim.EmulatedEntrypoint/Controllers/PackController.cs @@ -259,6 +259,20 @@ public class PackController : SVSimController }; } + [HttpPost("get_leader_skin_owned_status")] + public ActionResult>> GetLeaderSkinOwnedStatus( + [FromBody] PackGetLeaderSkinOwnedStatusRequest _) + { + if (!TryGetViewerId(out long __)) return Unauthorized(); + + // ClanType range MIN..MAX per spec (CardBasePrm.ClanType). 0..8 inclusive. + // Each bucket is `{}` — no curated leader-skin catalog per pack yet. + var result = new Dictionary>(9); + for (int classId = 0; classId <= 8; classId++) + result[classId.ToString()] = new Dictionary(); + return result; + } + [HttpPost("open")] [HttpPost("/tutorial/pack_open")] public async Task> Open(PackOpenRequest request) diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Pack/PackGetLeaderSkinOwnedStatusRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Pack/PackGetLeaderSkinOwnedStatusRequest.cs new file mode 100644 index 00000000..30160824 --- /dev/null +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/Pack/PackGetLeaderSkinOwnedStatusRequest.cs @@ -0,0 +1,13 @@ +using MessagePack; +using System.Text.Json.Serialization; +using SVSim.EmulatedEntrypoint.Models.Dtos.Requests; + +namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Pack; + +[MessagePackObject] +public class PackGetLeaderSkinOwnedStatusRequest : BaseRequest +{ + [JsonPropertyName("parent_gacha_id")] + [Key("parent_gacha_id")] + public int ParentGachaId { get; set; } +} diff --git a/SVSim.UnitTests/Controllers/PackControllerLeaderSkinOwnedStatusTests.cs b/SVSim.UnitTests/Controllers/PackControllerLeaderSkinOwnedStatusTests.cs new file mode 100644 index 00000000..10f17d2c --- /dev/null +++ b/SVSim.UnitTests/Controllers/PackControllerLeaderSkinOwnedStatusTests.cs @@ -0,0 +1,34 @@ +using System.Net; +using System.Text; +using System.Text.Json; +using NUnit.Framework; +using SVSim.UnitTests.Infrastructure; + +namespace SVSim.UnitTests.Controllers; + +public class PackControllerLeaderSkinOwnedStatusTests +{ + [Test] + public async Task GetLeaderSkinOwnedStatus_returns_nine_empty_buckets() + { + using var factory = new SVSimTestFactory(); + long viewerId = await factory.SeedViewerAsync(tutorialState: 0); + using var client = factory.CreateAuthenticatedClient(viewerId); + + var requestJson = """{"parent_gacha_id":99047,"viewer_id":"0","steam_id":0,"steam_session_ticket":""}"""; + var response = await client.PostAsync("/pack/get_leader_skin_owned_status", + new StringContent(requestJson, Encoding.UTF8, "application/json")); + + Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK)); + + var body = await response.Content.ReadAsStringAsync(); + using var doc = JsonDocument.Parse(body); + // Per spec: keys "0".."8" inclusive, each an empty object. + for (int classId = 0; classId <= 8; classId++) + { + var bucket = doc.RootElement.GetProperty(classId.ToString()); + Assert.That(bucket.ValueKind, Is.EqualTo(JsonValueKind.Object)); + Assert.That(bucket.EnumerateObject().Count(), Is.EqualTo(0)); + } + } +}