fix(rank-battle): use real rm_ai_setting.csv ai_id values in BotRoster

Phase 3 shipped placeholder ai_id values 4001..4008, which the client's
RankMatchAISettingList.GetSettingData() couldn't resolve — the lookup
is .First() against the rm_ai_setting.csv master table and throws
InvalidOperationException ("Sequence contains no matching element")
when the id isn't present. Surfaced on live smoke as a Unity error
during battle load:

  Wizard.RankMatchAISettingDataSet.GetSettingData (System.Int32 enemyAiId)
  BattleUI+<WaitForSetUp>d__9.MoveNext ()

Replaced with the series-1 enemy_ai_id per class from
data_dumps/client-assets/rm_ai_setting.csv:
  1111=Forest, 1121=Sword, 1131=Rune, 1141=Dragon,
  1151=Shadow, 1161=Blood, 1171=Haven, 1181=Portal

Practice mode's AI catalog (practice_ai_setting.csv) uses a different
schema keyed by (class_id, difficulty) with no enemy_ai_id field, so
practice ids aren't reusable here.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-02 09:41:38 -04:00
parent bf783639c1
commit 45c4461515
2 changed files with 20 additions and 14 deletions

View File

@@ -3,10 +3,13 @@ using SVSim.BattleNode.Bridge;
namespace SVSim.EmulatedEntrypoint.Matching;
/// <summary>
/// Phase 3 hardcoded fixture: one stub bot per class (1..8). <c>ai_id</c>
/// values 4001..4008 are placeholders per the existing
/// <c>docs/api-spec/endpoints/post-login/rank-battle/ai-start.md</c> TODO —
/// no live capture exists to validate the real prod catalog.
/// Phase 3 hardcoded fixture: one stub bot per class (1..8). <c>ai_id</c> values are
/// the "series 1" tier from the client's <c>rm_ai_setting.csv</c> master table
/// (<c>1111</c>=Forest, <c>1121</c>=Sword, … <c>1181</c>=Portal). The client's
/// <c>RankMatchAISettingList.GetSettingData(aiId)</c> calls <c>.First(...)</c> against
/// this table and throws <c>InvalidOperationException</c> if the id is absent — so the
/// ids MUST match. See <c>data_dumps/client-assets/rm_ai_setting.csv</c> for the full
/// catalog (32 rows: classes 1-8 × tiers 1-2 × deck variants 1-2).
/// </summary>
public sealed class BotRoster : IBotRoster
{
@@ -16,28 +19,28 @@ public sealed class BotRoster : IBotRoster
// sleeveId/emblemId/etc returned here.
private static readonly IReadOnlyList<AIBotProfile> Roster = new[]
{
new AIBotProfile(AiId: 4001, CountryCode: "NONE", UserName: "Forestcraft AI",
new AIBotProfile(AiId: 1111, CountryCode: "NONE", UserName: "Forestcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 1, CharaId: 1, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 4002, CountryCode: "NONE", UserName: "Swordcraft AI",
new AIBotProfile(AiId: 1121, CountryCode: "NONE", UserName: "Swordcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 2, CharaId: 2, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 4003, CountryCode: "NONE", UserName: "Runecraft AI",
new AIBotProfile(AiId: 1131, CountryCode: "NONE", UserName: "Runecraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 3, CharaId: 3, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 4004, CountryCode: "NONE", UserName: "Dragoncraft AI",
new AIBotProfile(AiId: 1141, CountryCode: "NONE", UserName: "Dragoncraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 4, CharaId: 4, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 4005, CountryCode: "NONE", UserName: "Shadowcraft AI",
new AIBotProfile(AiId: 1151, CountryCode: "NONE", UserName: "Shadowcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 5, CharaId: 5, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 4006, CountryCode: "NONE", UserName: "Bloodcraft AI",
new AIBotProfile(AiId: 1161, CountryCode: "NONE", UserName: "Bloodcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 6, CharaId: 6, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 4007, CountryCode: "NONE", UserName: "Havencraft AI",
new AIBotProfile(AiId: 1171, CountryCode: "NONE", UserName: "Havencraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 7, CharaId: 7, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 4008, CountryCode: "NONE", UserName: "Portalcraft AI",
new AIBotProfile(AiId: 1181, CountryCode: "NONE", UserName: "Portalcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 8, CharaId: 8, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
};