Things were working, suddenly regressed

This commit is contained in:
gamer147
2026-05-23 18:14:42 -04:00
parent 56d3cf0ec8
commit 66184b3685
31 changed files with 1493 additions and 97 deletions

View File

@@ -4,7 +4,9 @@ using SVSim.Database;
using SVSim.Database.Enums;
using SVSim.Database.Models;
using SVSim.Database.Repositories.Deck;
using SVSim.Database.Repositories.Globals;
using SVSim.EmulatedEntrypoint.Constants;
using SVSim.EmulatedEntrypoint.Extensions;
using SVSim.EmulatedEntrypoint.Models.Dtos;
using SVSim.EmulatedEntrypoint.Models.Dtos.Common;
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Common;
@@ -16,27 +18,64 @@ namespace SVSim.EmulatedEntrypoint.Controllers;
public class DeckController : SVSimController
{
private readonly IDeckRepository _deckRepository;
private readonly IGlobalsRepository _globalsRepository;
private readonly SVSimDbContext _dbContext;
public DeckController(IDeckRepository deckRepository, SVSimDbContext dbContext)
private static readonly System.Text.Json.JsonSerializerOptions JsonbReadOptions = new()
{
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.SnakeCaseLower,
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString,
};
public DeckController(IDeckRepository deckRepository, IGlobalsRepository globalsRepository, SVSimDbContext dbContext)
{
_deckRepository = deckRepository;
_globalsRepository = globalsRepository;
_dbContext = dbContext;
}
// TODO: API-side deck_format values may not match the Format enum (see audit on /load/index
// open question — `Data.FormatConvertApi` reverse-mapping not yet captured). For now we cast
// directly; verify against live traffic and add a conversion table if mismatched.
private static Format AsFormat(int apiValue) => (Format)apiValue;
// Request deck_format fields arrive as wire ints (MessagePack-CSharp doesn't honor STJ
// converters on request DTOs, so request DTO properties stay typed as int). Route through
// FromApi here so controllers always work in internal Format space when comparing /
// persisting.
private static Format AsFormat(int apiValue) => FormatExtensions.FromApi(apiValue);
[HttpPost("info")]
public async Task<ActionResult<DeckListResponse>> Info(DeckInfoRequest request)
{
if (!TryGetViewerId(out long viewerId)) return Unauthorized();
var decks = await _deckRepository.GetDecks(viewerId, AsFormat(request.DeckFormat));
// Globals — same shape every call; could be cached if it becomes a hotspot.
var defaultDecks = await _globalsRepository.GetDefaultDecks();
var leaderSkinSettings = await _globalsRepository.GetDefaultLeaderSkinSettings();
return new DeckListResponse
{
UserDeckList = decks.Select(d => new UserDeck(d)).ToList()
UserDeckList = decks.Select(d => new UserDeck(d)).ToList(),
DefaultDeckList = defaultDecks.ToDictionary(
d => d.Id.ToString(),
d => new DefaultDeck
{
DeckNo = d.DeckNo,
ClassId = d.ClassId,
SleeveId = d.SleeveId,
LeaderSkinId = d.LeaderSkinId,
DeckName = d.DeckName,
CardIdArray = System.Text.Json.JsonSerializer.Deserialize<List<long>>(d.CardIdArray, JsonbReadOptions) ?? new(),
}),
UserLeaderSkinSettingList = leaderSkinSettings.ToDictionary(
s => s.Id.ToString(),
s => new DefaultLeaderSkinSetting
{
ClassId = s.ClassId,
IsRandomLeaderSkin = s.IsRandomLeaderSkin,
LeaderSkinId = s.LeaderSkinId,
}),
// trial_deck_list: empty in 2026-05-23 prod; populated during tutorial campaigns —
// entry shape TBD until a capture lands with active content.
TrialDeckList = new(),
MaintenanceCardList = new(), // sourced from same place as /load/index when wired
};
}