Optimize OrganizeTroopsCommandSelector for better responsiveness

Performance improvements:
- Remove redundant Update() calls in PlusClickedImpl methods - the caller
  (UpdateTable or MaxClickedImpl) calls Update() when needed
- Remove unused Update() call in MinusClicked (result was never used)
- Cache extraTroops counts by type to avoid repeated LINQ queries on each
  battalion row
- Fix somethingChanged check to inspect fields directly instead of calling
  expensive Update() method inside Exists()
- Remove duplicate maxAllButton.SetActive(false) call

These changes reduce the number of object allocations and iterations
performed on each button click, improving UI responsiveness.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-20 09:27:30 -08:00
co-authored by Claude Opus 4.5
parent 68cdf625f4
commit 888dbbc62f
@@ -224,13 +224,13 @@ namespace eagle {
tp => tp.TypeId == battalionTypeId && tp.MeetsRequirements);
}
private void MaybeActivateRow(EventBasedTable table, BattalionTypeId battalionTypeId) {
private void MaybeActivateRow(
EventBasedTable table,
BattalionTypeId battalionTypeId,
Dictionary<BattalionTypeId, int> extraTroopsByType) {
var parent = table.gameObject.transform.parent;
var allowed = TypeIsAllowed(battalionTypeId) ||
extraTroops.Where(tfb => tfb.type == battalionTypeId)
.Select(tfb => tfb.count)
.Sum() > 0;
var allowed = TypeIsAllowed(battalionTypeId) || extraTroopsByType[battalionTypeId] > 0;
table.gameObject.GetComponent<OrganizeExtrasTable>().Set(
allowed,
@@ -251,12 +251,12 @@ namespace eagle {
parent.GetComponentInChildren<RawImage>().color = color;
}
private void MaybeActivateRows() {
MaybeActivateRow(lightInfantryTable, BattalionTypeId.LightInfantry);
MaybeActivateRow(heavyInfantryTable, BattalionTypeId.HeavyInfantry);
MaybeActivateRow(longbowmenTable, BattalionTypeId.Longbowmen);
MaybeActivateRow(dragoonsTable, BattalionTypeId.LightCavalry);
MaybeActivateRow(knightsTable, BattalionTypeId.HeavyCavalry);
private void MaybeActivateRows(Dictionary<BattalionTypeId, int> extraTroopsByType) {
MaybeActivateRow(lightInfantryTable, BattalionTypeId.LightInfantry, extraTroopsByType);
MaybeActivateRow(heavyInfantryTable, BattalionTypeId.HeavyInfantry, extraTroopsByType);
MaybeActivateRow(longbowmenTable, BattalionTypeId.Longbowmen, extraTroopsByType);
MaybeActivateRow(dragoonsTable, BattalionTypeId.LightCavalry, extraTroopsByType);
MaybeActivateRow(knightsTable, BattalionTypeId.HeavyCavalry, extraTroopsByType);
}
protected override void SetUpUI() {
@@ -330,7 +330,8 @@ namespace eagle {
} else
return false;
eb.Update(existingBattalions);
// Note: We don't call Update() here - the caller (UpdateTable or MaxClickedImpl)
// will call it when needed. This avoids redundant recalculations.
return true;
}
@@ -367,7 +368,6 @@ namespace eagle {
}
// Remove original troops
else {
var updated = eb.Update(existingBattalions);
var availableToRemove = eb.Original.Size - eb.troopsRemoved;
var newlyRemovedCount = Math.Min(KeyModifiedAmount.Amount(), availableToRemove);
@@ -464,7 +464,8 @@ namespace eagle {
} else
return false;
newB.Update(existingBattalions);
// Note: We don't call Update() here - the caller (UpdateTable or MaxClickedImpl)
// will call it when needed. This avoids redundant recalculations.
return true;
}
@@ -653,7 +654,16 @@ namespace eagle {
{ BattalionTypeId.Longbowmen, 0 }
};
maxAllButton.gameObject.SetActive(false);
// Cache extra troop counts by type to avoid repeated LINQ queries
var extraTroopsByType = new Dictionary<BattalionTypeId, int> {
{ BattalionTypeId.LightInfantry, 0 },
{ BattalionTypeId.HeavyInfantry, 0 },
{ BattalionTypeId.LightCavalry, 0 },
{ BattalionTypeId.HeavyCavalry, 0 },
{ BattalionTypeId.Longbowmen, 0 }
};
foreach (var et in extraTroops) { extraTroopsByType[et.type] += et.count; }
foreach (var eb in existingBattalions) {
if (eb.dismissed) continue;
@@ -666,9 +676,7 @@ namespace eagle {
newRow.MaxButtonClickedCallback = () => MaxClicked(eb);
newRow.DismissButtonClickedCallback = () => DismissClicked(eb);
bool canAugment =
TypeIsAllowed(eb.TypeId) ||
extraTroops.Where(tfb => tfb.type == eb.TypeId).Sum(tfb => tfb.count) > 0;
bool canAugment = TypeIsAllowed(eb.TypeId) || extraTroopsByType[eb.TypeId] > 0;
newRow.CanAugment = canAugment;
if (eb.Count < eb.Capacity) {
@@ -739,15 +747,18 @@ namespace eagle {
if (!sufficient) { _disabledReason = "Not enough gold"; }
// Also check that something has changed
// Check newBattalion fields directly instead of calling Update() which is expensive
bool somethingChanged =
(newBattalions.Exists(b => b.Update(existingBattalions).Size > 0) ||
(newBattalions.Exists(
b => b.newBattalion.NewTroops > 0 ||
b.newBattalion.TroopsFromOtherBattalion.Count > 0) ||
existingBattalions.Exists(eb => eb.changed != null || eb.troopsRemoved > 0));
if (!somethingChanged) { _disabledReason = "No battalions have changed"; }
_enableCommit = sufficient && somethingChanged;
resetAllButton.gameObject.SetActive(somethingChanged);
MaybeActivateRows();
MaybeActivateRows(extraTroopsByType);
}
public override AvailableCommand.SealedValueOneofCase CommandType =>