FixtureProvider.Populate for 0x21000023 was binding only
InventoryController and omitting PaperdollController, so the
~21 equip slots rendered empty even though sample equipped items
existed in the table. Also, the three per-list empty-slot
sprites were not being resolved from the dat (contentsEmpty /
sideBagEmpty / mainPackEmpty all defaulted to 0), so the slot cells
had no background art.
Fixes:
- FixtureProvider.Populate gains a DatCollection dats param
(mirrors the GameWindow.OnLoad lookup at line 2233-2235).
The 0x21000023 case now resolves all three empty sprites via
ItemListCellTemplate.ResolveEmptySprite and passes them to
InventoryController.Bind.
- PaperdollController.Bind is now called after InventoryController
in the same 0x21000023 case, matching GameWindow:2257-2265
(same layout subtree, contentsEmpty as the equip-slot placeholder,
sendWield: null since there is no live session in the studio).
- StudioWindow.OnLoad passes _dats! to the updated Populate signature.
SampleData.AddEquipped was already correct: MoveItem(guid, PlayerGuid,
-1, equipMask) at ClientObjectTable.cs:134 sets
CurrentlyEquippedLocation = newEquipLocation and calls Reindex which
places the item in _containerIndex[PlayerGuid]. No SampleData change
needed.
Tests: 2 new assertions in FixtureProviderTests —
sideBags_matchInventoryControllerFilter (Type.HasFlag(Container)
|| ItemsCapacity > 0 filter must match both bags) and
equippedItems_retainLocationAndAreInContents (equipped items have
CurrentlyEquippedLocation != None AND appear in GetContents so the
paperdoll controller can find them). 604 pass / 2 skip / 0 fail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task 4 of the UI Studio plan: adds SampleData (static ClientObjectTable
builder with a synthetic player, 6 loose items, 2 side bags, and 3 equipped
pieces) and FixtureProvider (switches on layoutId and calls the production
controller Bind methods — VitalsController, ToolbarController,
InventoryController — so the studio previews panels with plausible data
instead of empty widgets).
Icon ids approach: raw-resolve stub — resolves the base iconId via
RenderStack.ResolveChrome and returns the GL handle directly. This is v1
(single-layer icon); the full 5-layer IconComposer composite is a live-game
concern, not a layout-preview concern.
StudioWindow wires FixtureProvider.Populate after _source.Load; the
ClientObjectTable is stored on _objects so controller event subscriptions
(ObjectAdded/ObjectMoved) remain live for the window's lifetime.
4 new FixtureProviderTests (SampleTable_hasPackContents,
SampleTable_hasWeaponAndArmor, SampleTable_hasEquippedItems,
SampleTable_hasSideBags) — all pass. Full App suite: 602 passed / 2
skipped (pre-existing) / 0 failed. Build green.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task 2 of the acdream UI Studio plan. Adds three new files under
src/AcDream.App/Studio/ and one new test file:
- StudioOptions.cs: record + Parse() for the ui-studio CLI args (positional
dat dir or ACDREAM_DAT_DIR, --layout 0xNNNN, --markup <path>; defaults to
vitals 0x2100006C when neither layout nor markup given).
- LayoutSource.cs: wraps LayoutImporter.Import for dat-backed layouts; markup
path sets LastError "markup unsupported (Task 6)" and returns null for now.
Exposes Kind / LayoutId / MarkupPath / LastError / CurrentLayout / Reload().
- StudioWindow.cs: Silk.NET 1280×720 GL 4.3 window; boots RenderBootstrap,
wires input to UiHost, loads the panel via LayoutSource, adds the root to
UiHost.Root.AddChild. QualitySettings resolved the same way GameWindow.Run()
does (SettingsStore → QualitySettings.From → WithEnvOverrides).
- Program.cs: ui-studio dispatch at the top of top-level statements (before
the dat-dir parse) so `dotnet run -- ui-studio` routes to StudioWindow.
- LayoutSourceTests.cs: dat-gated test (skips when dats absent); verifies that
the vitals LayoutDesc (0x2100006C) loads, root is non-null, byId contains the
vitals root element (0x100005F9), and Kind == DatLayout. Passes (1/1 with dats
present; silently skips on CI).
Note: the spec asserts FindElement(0x2100006Cu) — that id is the LayoutDesc
dat id, not a widget element id. The actual vitals root element id is 0x100005F9
(confirmed from the vitals_2100006C.json fixture). The test uses the correct
element id and documents the discrepancy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>