Class leader fixes

This commit is contained in:
gamer147
2026-05-26 10:01:37 -04:00
parent b6966ece6e
commit 9090086a47
12 changed files with 2861 additions and 81 deletions

View File

@@ -68,7 +68,6 @@ public class GlobalsImporter
if (deckInfo.HasValue)
{
total += await ImportDefaultDecks(context, deckInfo.Value);
total += await ImportDefaultLeaderSkinSettings(context, deckInfo.Value);
}
if (paymentItemList.HasValue)
@@ -716,28 +715,6 @@ public class GlobalsImporter
return created + updated;
}
// ---------- Deck/info: Default Leader Skin Settings ----------
private async Task<int> ImportDefaultLeaderSkinSettings(SVSimDbContext context, JsonElement deckInfo)
{
if (!deckInfo.TryGetProperty("user_leader_skin_setting_list", out var info) || info.ValueKind != JsonValueKind.Object) return 0;
var existing = await context.DefaultLeaderSkinSettings.ToDictionaryAsync(e => e.Id);
int created = 0, updated = 0;
foreach (var kv in info.EnumerateObject())
{
if (!int.TryParse(kv.Name, out int classId)) continue;
var v = kv.Value;
var entry = existing.TryGetValue(classId, out var ex) ? ex : new DefaultLeaderSkinSettingEntry { Id = classId };
entry.IsRandomLeaderSkin = GetInt(v, "is_random_leader_skin");
entry.LeaderSkinId = GetInt(v, "leader_skin_id");
if (ex is null) { context.DefaultLeaderSkinSettings.Add(entry); created++; }
else updated++;
}
Console.WriteLine($"[GlobalsImporter] DefaultLeaderSkinSettings: +{created}/~{updated}");
return created + updated;
}
// ---------- Payment: Item list (Steam/PC storefront, dict-keyed by store_product_id) ----------
private async Task<int> ImportPaymentItems(SVSimDbContext context, JsonElement payment)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SVSim.Database.Migrations
{
/// <inheritdoc />
public partial class DropDefaultLeaderSkinSettings : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "DefaultLeaderSkinSettings");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "DefaultLeaderSkinSettings",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false),
ClassId = table.Column<int>(type: "integer", nullable: false),
DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DateUpdated = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
IsRandomLeaderSkin = table.Column<int>(type: "integer", nullable: false),
LeaderSkinId = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_DefaultLeaderSkinSettings", x => x.Id);
});
}
}
}

View File

@@ -824,31 +824,6 @@ namespace SVSim.Database.Migrations
b.ToTable("DefaultDecks");
});
modelBuilder.Entity("SVSim.Database.Models.DefaultLeaderSkinSettingEntry", b =>
{
b.Property<int>("Id")
.HasColumnType("integer");
b.Property<int>("ClassId")
.HasColumnType("integer");
b.Property<DateTime>("DateCreated")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DateUpdated")
.HasColumnType("timestamp with time zone");
b.Property<int>("IsRandomLeaderSkin")
.HasColumnType("integer");
b.Property<int>("LeaderSkinId")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("DefaultLeaderSkinSettings");
});
modelBuilder.Entity("SVSim.Database.Models.DegreeEntry", b =>
{
b.Property<int>("Id")

View File

@@ -1,13 +0,0 @@
using SVSim.Database.Common;
namespace SVSim.Database.Models;
/// <summary>One row per class: which leader skin is default and whether random rotation is on.</summary>
public class DefaultLeaderSkinSettingEntry : BaseEntity<int>
{
public int ClassId { get => Id; set => Id = value; }
public int IsRandomLeaderSkin { get; set; }
public int LeaderSkinId { get; set; }
}

View File

@@ -41,9 +41,6 @@ public class GlobalsRepository : IGlobalsRepository
public Task<List<DefaultDeckEntry>> GetDefaultDecks() =>
_dbContext.DefaultDecks.AsNoTracking().ToListAsync();
public Task<List<DefaultLeaderSkinSettingEntry>> GetDefaultLeaderSkinSettings() =>
_dbContext.DefaultLeaderSkinSettings.AsNoTracking().ToListAsync();
public Task<ArenaSeasonConfig?> GetCurrentArenaSeason() =>
_dbContext.ArenaSeasons.AsNoTracking().FirstOrDefaultAsync(e => e.Id == 1);

View File

@@ -13,7 +13,6 @@ public interface IGlobalsRepository
Task<List<MyRotationAbilityEntry>> GetMyRotationAbilities();
Task<List<AvatarAbilityEntry>> GetAvatarAbilities();
Task<List<DefaultDeckEntry>> GetDefaultDecks();
Task<List<DefaultLeaderSkinSettingEntry>> GetDefaultLeaderSkinSettings();
Task<ArenaSeasonConfig?> GetCurrentArenaSeason();
Task<List<SpotCardEntry>> GetSpotCards();
Task<List<ReprintedCardEntry>> GetReprintedCards();

View File

@@ -44,7 +44,6 @@ public class SVSimDbContext : DbContext
public DbSet<MyRotationAbilityEntry> MyRotationAbilities => Set<MyRotationAbilityEntry>();
public DbSet<AvatarAbilityEntry> AvatarAbilities => Set<AvatarAbilityEntry>();
public DbSet<DefaultDeckEntry> DefaultDecks => Set<DefaultDeckEntry>();
public DbSet<DefaultLeaderSkinSettingEntry> DefaultLeaderSkinSettings => Set<DefaultLeaderSkinSettingEntry>();
public DbSet<ArenaSeasonConfig> ArenaSeasons => Set<ArenaSeasonConfig>();
public DbSet<SpotCardEntry> SpotCards => Set<SpotCardEntry>();
public DbSet<ReprintedCardEntry> ReprintedCards => Set<ReprintedCardEntry>();

View File

@@ -125,7 +125,7 @@ public class DeckController : SVSimController
}),
UserLeaderSkinSettingList = viewerClasses.ToDictionary(
vc => vc.Id.ToString(),
vc => new DefaultLeaderSkinSetting
vc => new UserLeaderSkinSetting
{
ClassId = vc.Id,
IsRandomLeaderSkin = 0, // random-skin mode (per-class shuffle pool) not yet persisted

View File

@@ -46,10 +46,11 @@ public class DeckListResponse
[Key("default_deck_list")] public Dictionary<string, DefaultDeck> DefaultDeckList { get; set; } = new();
/// <summary>
/// Default leader skin per class, keyed by class_id as string.
/// Per-class leader skin setting (active skin id) for the requesting viewer, keyed by
/// class_id as string.
/// </summary>
[JsonPropertyName("user_leader_skin_setting_list")]
[Key("user_leader_skin_setting_list")] public Dictionary<string, DefaultLeaderSkinSetting> UserLeaderSkinSettingList { get; set; } = new();
[Key("user_leader_skin_setting_list")] public Dictionary<string, UserLeaderSkinSetting> UserLeaderSkinSettingList { get; set; } = new();
/// <summary>
/// Trial / tutorial-specific decks. Prod emits this on <c>/deck/info</c> (All format) but

View File

@@ -4,12 +4,13 @@ using System.Text.Json.Serialization;
namespace SVSim.EmulatedEntrypoint.Models.Dtos;
/// <summary>
/// Default leader skin per class (8 entries — one per class). Surfaced under
/// <c>/deck/info data.user_leader_skin_setting_list</c>. Despite the <c>user_</c> prefix on the
/// wire, this is GLOBAL data (same for every viewer) — naming is the client's, not ours.
/// Per-class entry of <c>/deck/info data.user_leader_skin_setting_list</c>. Per-viewer state:
/// each viewer's class-level "active leader skin" preference, used as a fallback when a deck
/// has <c>leader_skin_id == 0</c>. Sourced from <c>ViewerClassData.LeaderSkin</c>; mutated by
/// <c>POST /leader_skin/set</c>.
/// </summary>
[MessagePackObject]
public class DefaultLeaderSkinSetting
public class UserLeaderSkinSetting
{
[JsonPropertyName("class_id")]
[Key("class_id")]

View File

@@ -197,14 +197,11 @@ public class GlobalsRepositoryTests
"Each starter deck should serialize multiple card IDs in card_id_array.");
}
[Test]
public async Task GetDefaultLeaderSkinSettings_returns_8_entries()
{
var (factory, repo) = await SetupAsync();
using var _ = factory;
var skins = await repo.GetDefaultLeaderSkinSettings();
Assert.That(skins.Count, Is.EqualTo(8));
}
// Note: GetDefaultLeaderSkinSettings was removed from IGlobalsRepository in the
// 2026-05-26 per-viewer leader-skin refactor. /deck/info now sources
// user_leader_skin_setting_list from viewer.Classes (each ViewerClassData carries the
// active LeaderSkin), and /leader_skin/set mutates it. Coverage moved to
// LeaderSkinControllerTests.
// Note: GetGameConfiguration was removed from IGlobalsRepository in the 2026-05-24 config
// refactor — Rotation/Challenge/etc. now load via IGameConfigService. See