Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Core/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,22 @@ void ControlBar::update()
exitPosition = obj->getObjectExitInterface()->getRallyPoint();

showRallyPoint(exitPosition);

ContainModuleInterface* observerContain = obj ? obj->getContain() : nullptr;
Bool showObserverInventory = (observerContain != nullptr && observerContain->getContainMax() > 0);

if (showObserverInventory && m_observerLookAtPlayer == nullptr)
Comment on lines +1483 to +1486

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Inventory slots overflow 🐞 Bug ☼ Reliability

ControlBar::update() now switches observers into CB_CONTEXT_STRUCTURE_INVENTORY for any selected
object with getContainMax() > 0, but the structure inventory UI only supports 10 occupant slots. If
a container ever has >10 contained objects (e.g., tunnel networks when MaxTunnelCapacity is
configured above 10), populateStructureInventory() will call populateButtonProc() past the supported
slot count, tripping the MAX_STRUCTURE_INVENTORY_BUTTONS assert and/or overwriting non-inventory
buttons.
Agent Prompt
### Issue description
Observer mode now routes any selectable container (ContainMax > 0) into `CB_CONTEXT_STRUCTURE_INVENTORY`. The structure inventory UI is hard-limited to `MAX_STRUCTURE_INVENTORY_BUTTONS` (10). If `iterateContained()` yields more than 10 occupants, `populateButtonProc()` hits its `DEBUG_ASSERTCRASH` (and in non-assert builds can start repurposing the Stop/Evacuate buttons and potentially go beyond UI expectations).

### Issue Context
- `ControlBar::update()` (observer branch) uses only `getContainMax() > 0` as the gate.
- `populateStructureInventory()` iterates *all* contained objects and calls `populateButtonProc()`.
- `populateButtonProc()` asserts `buttonIndex < MAX_STRUCTURE_INVENTORY_BUTTONS`.
- Tunnel network capacity is configurable via `GlobalData::m_maxTunnelCapacity` (INI: `MaxTunnelCapacity`), so it can exceed 10.

### Fix Focus Areas
- Core/GameEngine/Source/GameClient/GUI/ControlBar/ControlBar.cpp[1483-1496]
- Core/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarStructureInventory.cpp[63-90]
- Core/GameEngine/Source/GameClient/GUI/ControlBar/ControlBarStructureInventory.cpp[179-196]

### What to change
Implement *one* of these safe guards (preferably both A and B):
1. **A (UI-level hardening):** In `populateButtonProc()`, if `buttonIndex >= MAX_STRUCTURE_INVENTORY_BUTTONS`, return early (do not write into `m_containData` / do not enable controls). This prevents asserts/crashes and prevents Stop/Evacuate slots from being repurposed.
2. **B (observer routing guard):** In observer `update()`, only route to `CB_CONTEXT_STRUCTURE_INVENTORY` when `observerContain->getContainCount() <= MAX_STRUCTURE_INVENTORY_BUTTONS` (or clamp display to 10 with a clear rule). If count exceeds, fall back to `CB_CONTEXT_OBSERVER_LIST` or add paging/scrolling support.

Include an explicit comment explaining the 10-slot UI limitation so future changes to tunnel capacity don’t reintroduce the problem.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

{
if (m_currContext != CB_CONTEXT_STRUCTURE_INVENTORY || m_currentSelectedDrawable != drawToEvaluateFor)
switchToContext(CB_CONTEXT_STRUCTURE_INVENTORY, drawToEvaluateFor);
else
updateContextStructureInventory();
}
else if (m_currContext != CB_CONTEXT_OBSERVER_LIST)
{
switchToContext(CB_CONTEXT_OBSERVER_LIST, nullptr);
}

return;
}

Expand Down
Loading