
TITLE
Terminal inventory MainThreadFreeze caused by non-virtualized realization of hundreds of InventoryItemModel controls

GAME / BUILD
Space Engineers 2
Version: 2.4.0.95
Game2.Client.dll SHA256:
fdcd1c1eb01433be994c87893a88f720325bf93c1e797930d79859ed664bb9ba

SUMMARY
Opening terminal inventory on a sufficiently large connected inventory network can stall the main/UI thread for multiple seconds and trigger the VRAGE MainThreadFreeze watchdog.

The freeze was isolated to the client UI path. A managed stack captured during an active watchdog freeze shows the main thread building Keen's compiled Avalonia inventory item template, adding controls to the visual tree, styling them, and measuring a WrapPanel.

The exact compiled XAML closure on the frozen main thread maps to:
avares://Game2.Client/UI/TerminalScreen/Inventory/InventoryItem.axaml

The affected template is:
CompiledAvaloniaXaml.!AvaloniaResources+XamlClosure_1216+XamlClosure_1218.Build
Build token: 0x06014D8E
Parent closure token: 0x06014D8A

REPRODUCTION
1. Load a save with a large conveyor-connected inventory network.
2. Open a terminal inventory from a cockpit or large Cargo750 container.
3. Repeat opening/closing terminal inventory or switching among connected inventories.
4. On the affected save, the UI can stall for several seconds and trigger MainThreadFreeze.

Observed examples before the diagnostic display cap:
- Cockpit terminal open -> MainThreadFreeze.
- Cargo750 terminal opens -> MainThreadFreeze.
- Repeated freezes between approximately 3 and 13 seconds in tested runs.
- Earlier capture run produced freezes of 12.6 s, 5.4 s, 11.6 s, and 9.5 s.

LIVE FREEZE STACK
During an active watchdog freeze, the main thread was captured in this path:

Avalonia.Reactive.LightweightObservableBase.PublishNext
Avalonia.AvaloniaObject.RaisePropertyChanged
Avalonia.Layout.Layoutable.OnVisualParentChanged
Avalonia.Visual.SetVisualParent
Avalonia.Collections.AvaloniaList.InsertRange
Avalonia.Controls.Panel.ChildrenChanged
Avalonia.Collections.AvaloniaList.Add
Game2.Client!CompiledAvaloniaXaml.!AvaloniaResources+XamlClosure_1216+XamlClosure_1218.Build
Avalonia.Markup.Xaml.Templates.TemplateContent.Load
Avalonia.Markup.Xaml.Templates.DataTemplate.Build
Avalonia.Controls.Presenters.ContentPresenter.UpdateChild
Avalonia.Controls.Presenters.ContentPresenter.ApplyTemplate
...
Avalonia.Controls.WrapPanel.MeasureOverride
Avalonia.Layout.LayoutManager.ExecuteMeasurePass
Avalonia.Layout.LayoutManager.ExecuteLayoutPass
...
Keen.VRage.UI.AvaloniaInterface.Rendering.DispatcherImpl.DispatchAllCalls
Keen.VRage.UI.EngineComponents.UIEngineComponent.UIManagerTick
...
Keen.Game2.Program.Main

This is active UI construction/layout work, not a conveyor traversal, inventory transfer, GC stop, or managed deadlock.

STATIC CLIENT CODE FINDINGS
InventoryGrid.ItemsFilled() enumerates every real InventoryItemModel in InventoryViewModel.InventoryItems and yields every one to the UI. If MaxStacks is present it also pads with null placeholders.

The problematic save showed many individual InventoryGrid instances containing hundreds of REAL client item models:
290
552
452
703
741
275
393
456
235
306
308
585
683
540
657
685
651
500

The outer terminal inventory UI also uses ordinary ItemsControl bindings for the connected inventory/container hierarchy. No inventory-path VirtualizingStackPanel was found in the decompiled target controls.

InventoryListViewModel.SetInventories(...) clears the current inventory-container list and then repopulates it, which can amplify the cost because terminal inventory controls can be rebuilt while streamed inventory state changes.

A/B CAUSAL TEST
A local diagnostic was created that does NOT modify:
- server inventory contents
- InventoryModel.Items
- InventoryDefinition
- MaxStacks
- conveyor behavior
- save data
- Workshop mod files

The diagnostic changes only the inner Avalonia PART_ItemsControl.ItemsSource for InventoryGrid, limiting the DISPLAYED real InventoryItemModel objects to the first 60.

Before:
- Full hundreds-of-real-item-model UI realization.
- MainThreadFreeze watchdog events reproduced repeatedly.

With display-only cap active:
- The diagnostic fired 280 DISPLAY-CAP events.
- Examples:
  realItems=290 displayed=60
  realItems=552 displayed=60
  realItems=703 displayed=60
  realItems=741 displayed=60
  realItems=683 displayed=60
  realItems=685 displayed=60
- Same save.
- Same cockpit.
- Same Cargo750 opened repeatedly.
- Gearforge terminal also opened.
- ZERO MainThreadFreeze events were present in the complete main game log for that run.

This is the strongest causal result: reducing only the number of InventoryItemModel controls presented to Avalonia eliminated the watchdog freezes without changing the underlying inventory data.

EXPECTED FIX AREA
The terminal inventory UI should avoid realizing hundreds of InventoryItem controls at once.

Likely fixes include:
- virtualizing the item grid / item presenter;
- paging or windowing the visible InventoryItemModel list;
- avoiding full control-tree rebuilds when streamed inventory containers change;
- preserving/reconciling existing container/item view models rather than clearing and recreating the complete hierarchy.

IMPORTANT
The local 60-item display cap is only an A/B diagnostic and is NOT a proposed gameplay fix because items after the first 60 are intentionally hidden from the rendered diagnostic UI.

The diagnostic DLL has been uninstalled after testing.

ATTACHED EVIDENCE
See README-EVIDENCE.txt for file descriptions and the evidence archive.

