Compare commits

...
Author SHA1 Message Date
adminandClaude Opus 4.6 b7a3baedda Fix free heroes table crash and upsert unaffiliated heroes (#6404)
Two fixes:

1. FreeHeroesTableController: rebuild the table if the hero count has
   changed since it was last set up, before updating selections. The
   crash occurred because SelectButtonIndex called
   UpdateUnaffiliatedHeroSelections without first rebuilding the table,
   so a model update arriving between table setup and button click caused
   an index-out-of-range.

2. EagleGameModel: treat AddedUnaffiliatedHeroes as an upsert — replace
   the existing entry if one with the same HeroId already exists, rather
   than throwing. The server diff uses remove+add pairs for updates, but
   if a remove is missed (e.g. stale before-state after reconnect), the
   add should still converge to the correct state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 21:51:46 -08:00
2 changed files with 15 additions and 4 deletions
@@ -855,11 +855,18 @@ namespace eagle {
}
}
foreach (var added in nfi.AddedUnaffiliatedHeroes) {
if (province.FullInfo.UnaffiliatedHeroes.Any(uh => uh.HeroId == added.HeroId)) {
throw new InvalidOperationException(
$"Duplicate unaffiliated hero {added.HeroId} in province {cp.Id}");
var existingIndex = -1;
for (int i = 0; i < province.FullInfo.UnaffiliatedHeroes.Count; i++) {
if (province.FullInfo.UnaffiliatedHeroes[i].HeroId == added.HeroId) {
existingIndex = i;
break;
}
}
if (existingIndex >= 0) {
province.FullInfo.UnaffiliatedHeroes[existingIndex] = added;
} else {
province.FullInfo.UnaffiliatedHeroes.Add(added);
}
province.FullInfo.UnaffiliatedHeroes.Add(added);
}
}
@@ -66,6 +66,10 @@ namespace eagle {
}
public void UpdateUnaffiliatedHeroSelections() {
if (UnaffiliatedHeroCount != unaffiliatedHeroesTable.RowCount) {
setUpUnaffiliatedHeroesTable();
return;
}
UnaffiliatedHeroes.Each(
(uh, i) => SetUnaffiliatedHeroRowSelections(
unaffiliatedHeroesTable.ComponentAt<UnaffiliatedHeroRowController>(i),