From d87f9beb81afcdafc6b291eb85830a874970c83c Mon Sep 17 00:00:00 2001 From: gamer147 Date: Tue, 2 Jun 2026 11:09:20 -0400 Subject: [PATCH] fix(rank-battle): use prod-verified bot cosmetic ids to unblock LoadOpponentAssets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Waiting for opponent" hang traced to BattleStartControl.IsReady never flipping true. That's gated by SBattleLoad.LoadOpponentAssets which calls ResourcesManager.LoadAssetGroupSync with the bot's {rank, emblemId, degreeId, countryCode} — and our placeholder ids (1/1/1/"NONE") don't resolve to any asset in the client's resource bundle, so the callback never fires. Replaced with the Scripted bot's known-good prod values: - SleeveId: 704141010 - EmblemId: 400001100 - DegreeId: 120027 - FieldId: 5 - CountryCode: "JPN" - IsOfficial: 0 These are the same ids ScriptedBotParticipant.Context uses, which we know load fine because the TK2 Scripted flow has been working end-to-end since Phase 2. Reference for the load chain (decompiled client): BattleUI.WaitForSetUp → m_SBattleLoad.WaitCallBack → BattleStartControl.SetUp → CheckAbleToInitialize → SBattleLoad.LoadOpponentAssets (SBattleLoad.cs:933) → ResourcesManager.LoadAssetGroupSync — hangs on missing assets Co-Authored-By: Claude Opus 4.7 --- .../Matching/BotRoster.cs | 72 ++++++++++++++----- SVSim.UnitTests/Matching/BotRosterTests.cs | 2 +- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/SVSim.EmulatedEntrypoint/Matching/BotRoster.cs b/SVSim.EmulatedEntrypoint/Matching/BotRoster.cs index 9fa7ed0..3e21e0a 100644 --- a/SVSim.EmulatedEntrypoint/Matching/BotRoster.cs +++ b/SVSim.EmulatedEntrypoint/Matching/BotRoster.cs @@ -19,29 +19,69 @@ public sealed class BotRoster : IBotRoster // sleeveId/emblemId/etc returned here. private static readonly IReadOnlyList Roster = new[] { - new AIBotProfile(AiId: 1111, CountryCode: "NONE", UserName: "Forestcraft AI", - SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0, + new AIBotProfile(AiId: 1111, CountryCode: "JPN", UserName: "Forestcraft AI", + // Cosmetic ids mirror the Scripted bot's prod-verified values + // (ScriptedProfiles / ScriptedBotParticipant.Context). Placeholder + // ids of 1 failed to resolve in ResourcesManager.LoadAssetGroupSync — + // LoadOpponentAssets (SBattleLoad.cs:933) hangs forever waiting for + // missing assets and the "Waiting for opponent" UI never closes. + SleeveId: 704141010, EmblemId: 400001100, DegreeId: 120027, FieldId: 5, IsOfficial: 0, ClassId: 1, CharaId: 1, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0), - new AIBotProfile(AiId: 1121, CountryCode: "NONE", UserName: "Swordcraft AI", - SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0, + new AIBotProfile(AiId: 1121, CountryCode: "JPN", UserName: "Swordcraft AI", + // Cosmetic ids mirror the Scripted bot's prod-verified values + // (ScriptedProfiles / ScriptedBotParticipant.Context). Placeholder + // ids of 1 failed to resolve in ResourcesManager.LoadAssetGroupSync — + // LoadOpponentAssets (SBattleLoad.cs:933) hangs forever waiting for + // missing assets and the "Waiting for opponent" UI never closes. + SleeveId: 704141010, EmblemId: 400001100, DegreeId: 120027, FieldId: 5, IsOfficial: 0, ClassId: 2, CharaId: 2, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0), - new AIBotProfile(AiId: 1131, CountryCode: "NONE", UserName: "Runecraft AI", - SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0, + new AIBotProfile(AiId: 1131, CountryCode: "JPN", UserName: "Runecraft AI", + // Cosmetic ids mirror the Scripted bot's prod-verified values + // (ScriptedProfiles / ScriptedBotParticipant.Context). Placeholder + // ids of 1 failed to resolve in ResourcesManager.LoadAssetGroupSync — + // LoadOpponentAssets (SBattleLoad.cs:933) hangs forever waiting for + // missing assets and the "Waiting for opponent" UI never closes. + SleeveId: 704141010, EmblemId: 400001100, DegreeId: 120027, FieldId: 5, IsOfficial: 0, ClassId: 3, CharaId: 3, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0), - new AIBotProfile(AiId: 1141, CountryCode: "NONE", UserName: "Dragoncraft AI", - SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0, + new AIBotProfile(AiId: 1141, CountryCode: "JPN", UserName: "Dragoncraft AI", + // Cosmetic ids mirror the Scripted bot's prod-verified values + // (ScriptedProfiles / ScriptedBotParticipant.Context). Placeholder + // ids of 1 failed to resolve in ResourcesManager.LoadAssetGroupSync — + // LoadOpponentAssets (SBattleLoad.cs:933) hangs forever waiting for + // missing assets and the "Waiting for opponent" UI never closes. + SleeveId: 704141010, EmblemId: 400001100, DegreeId: 120027, FieldId: 5, IsOfficial: 0, ClassId: 4, CharaId: 4, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0), - new AIBotProfile(AiId: 1151, CountryCode: "NONE", UserName: "Shadowcraft AI", - SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0, + new AIBotProfile(AiId: 1151, CountryCode: "JPN", UserName: "Shadowcraft AI", + // Cosmetic ids mirror the Scripted bot's prod-verified values + // (ScriptedProfiles / ScriptedBotParticipant.Context). Placeholder + // ids of 1 failed to resolve in ResourcesManager.LoadAssetGroupSync — + // LoadOpponentAssets (SBattleLoad.cs:933) hangs forever waiting for + // missing assets and the "Waiting for opponent" UI never closes. + SleeveId: 704141010, EmblemId: 400001100, DegreeId: 120027, FieldId: 5, IsOfficial: 0, ClassId: 5, CharaId: 5, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0), - new AIBotProfile(AiId: 1161, CountryCode: "NONE", UserName: "Bloodcraft AI", - SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0, + new AIBotProfile(AiId: 1161, CountryCode: "JPN", UserName: "Bloodcraft AI", + // Cosmetic ids mirror the Scripted bot's prod-verified values + // (ScriptedProfiles / ScriptedBotParticipant.Context). Placeholder + // ids of 1 failed to resolve in ResourcesManager.LoadAssetGroupSync — + // LoadOpponentAssets (SBattleLoad.cs:933) hangs forever waiting for + // missing assets and the "Waiting for opponent" UI never closes. + SleeveId: 704141010, EmblemId: 400001100, DegreeId: 120027, FieldId: 5, IsOfficial: 0, ClassId: 6, CharaId: 6, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0), - new AIBotProfile(AiId: 1171, CountryCode: "NONE", UserName: "Havencraft AI", - SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0, + new AIBotProfile(AiId: 1171, CountryCode: "JPN", UserName: "Havencraft AI", + // Cosmetic ids mirror the Scripted bot's prod-verified values + // (ScriptedProfiles / ScriptedBotParticipant.Context). Placeholder + // ids of 1 failed to resolve in ResourcesManager.LoadAssetGroupSync — + // LoadOpponentAssets (SBattleLoad.cs:933) hangs forever waiting for + // missing assets and the "Waiting for opponent" UI never closes. + SleeveId: 704141010, EmblemId: 400001100, DegreeId: 120027, FieldId: 5, IsOfficial: 0, ClassId: 7, CharaId: 7, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0), - new AIBotProfile(AiId: 1181, CountryCode: "NONE", UserName: "Portalcraft AI", - SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0, + new AIBotProfile(AiId: 1181, CountryCode: "JPN", UserName: "Portalcraft AI", + // Cosmetic ids mirror the Scripted bot's prod-verified values + // (ScriptedProfiles / ScriptedBotParticipant.Context). Placeholder + // ids of 1 failed to resolve in ResourcesManager.LoadAssetGroupSync — + // LoadOpponentAssets (SBattleLoad.cs:933) hangs forever waiting for + // missing assets and the "Waiting for opponent" UI never closes. + SleeveId: 704141010, EmblemId: 400001100, DegreeId: 120027, FieldId: 5, IsOfficial: 0, ClassId: 8, CharaId: 8, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0), }; diff --git a/SVSim.UnitTests/Matching/BotRosterTests.cs b/SVSim.UnitTests/Matching/BotRosterTests.cs index 9043595..b720321 100644 --- a/SVSim.UnitTests/Matching/BotRosterTests.cs +++ b/SVSim.UnitTests/Matching/BotRosterTests.cs @@ -34,7 +34,7 @@ public class BotRosterTests Assert.That(bot.ClassId, Is.InRange(1, 8)); Assert.That(bot.CharaId, Is.InRange(1, 8)); Assert.That(bot.UserName, Is.Not.Null.And.Not.Empty); - Assert.That(bot.CountryCode, Is.EqualTo("NONE")); + Assert.That(bot.CountryCode, Is.Not.Null.And.Not.Empty); } [Test]