feat(studio): FixtureProvider — sample data populates the 2-D panels
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>
This commit is contained in:
parent
101a35cc2d
commit
0bdc866c15
4 changed files with 402 additions and 0 deletions
114
src/AcDream.App/Studio/FixtureProvider.cs
Normal file
114
src/AcDream.App/Studio/FixtureProvider.cs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
using AcDream.App.Rendering;
|
||||
using AcDream.App.UI;
|
||||
using AcDream.App.UI.Layout;
|
||||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Net.Messages;
|
||||
|
||||
namespace AcDream.App.Studio;
|
||||
|
||||
/// <summary>
|
||||
/// Populates a loaded panel with sample data by calling the production
|
||||
/// controller Bind methods against <see cref="SampleData"/>.
|
||||
///
|
||||
/// <para>
|
||||
/// The studio is intentionally thin — there is no live game session, no
|
||||
/// server connection, and no network. FixtureProvider bridges that gap by
|
||||
/// feeding static fixtures (vitals percentages, a fake inventory, empty
|
||||
/// shortcut lists) so the bound widgets show plausible state instead of
|
||||
/// empty zeroes.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// <b>IconIds approach:</b> raw-resolve stub — resolve the base <c>iconId</c>
|
||||
/// via <see cref="RenderStack.ResolveChrome"/> and return the GL handle
|
||||
/// directly. This is intentionally simpler than GameWindow's full
|
||||
/// <see cref="IconComposer"/> (5-layer composite). The raw icon is enough
|
||||
/// to confirm the grid cells draw something in the studio; the full
|
||||
/// compositor is the live-game concern, not the layout preview concern.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static class FixtureProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Populate <paramref name="layout"/> with sample data appropriate for
|
||||
/// <paramref name="layoutId"/>. Calls the production controller Bind
|
||||
/// methods so the panel's widgets drive off the same code path as the
|
||||
/// full game.
|
||||
/// </summary>
|
||||
/// <param name="layoutId">The LayoutDesc dat id used to import the layout.</param>
|
||||
/// <param name="layout">The imported layout whose widgets to populate.</param>
|
||||
/// <param name="stack">The live render stack (for <see cref="RenderStack.ResolveChrome"/>
|
||||
/// and <see cref="RenderStack.VitalsDatFont"/>).</param>
|
||||
/// <param name="objects">A <see cref="ClientObjectTable"/> already seeded by
|
||||
/// <see cref="SampleData.BuildObjectTable"/>.</param>
|
||||
public static void Populate(
|
||||
uint layoutId,
|
||||
ImportedLayout layout,
|
||||
RenderStack stack,
|
||||
ClientObjectTable objects)
|
||||
{
|
||||
switch (layoutId)
|
||||
{
|
||||
case 0x2100006Cu: // vitals
|
||||
VitalsController.Bind(layout,
|
||||
healthPct: () => SampleData.HealthPct,
|
||||
staminaPct: () => SampleData.StaminaPct,
|
||||
manaPct: () => SampleData.ManaPct,
|
||||
healthText: () => "80/100",
|
||||
staminaText: () => "60/100",
|
||||
manaText: () => "90/100");
|
||||
break;
|
||||
|
||||
case 0x21000016u: // toolbar
|
||||
ToolbarController.Bind(
|
||||
layout,
|
||||
objects,
|
||||
shortcuts: () => System.Array.Empty<PlayerDescriptionParser.ShortcutEntry>(),
|
||||
iconIds: MakeIconIds(stack),
|
||||
useItem: _ => { },
|
||||
combatState: null,
|
||||
peaceDigits: null,
|
||||
warDigits: null,
|
||||
emptyDigits: null,
|
||||
sendAddShortcut: null,
|
||||
sendRemoveShortcut: null);
|
||||
break;
|
||||
|
||||
case 0x21000023u: // inventory
|
||||
InventoryController.Bind(
|
||||
layout,
|
||||
objects,
|
||||
playerGuid: () => SampleData.PlayerGuid,
|
||||
iconIds: MakeIconIds(stack),
|
||||
strength: () => 100,
|
||||
datFont: stack.VitalsDatFont);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown layout — no-op; the panel renders structurally.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Build the <c>iconIds</c> delegate for toolbar / inventory controllers.
|
||||
///
|
||||
/// <para>
|
||||
/// Raw-resolve stub: resolve the base <paramref name="iconId"/> (arg 2)
|
||||
/// via <see cref="RenderStack.ResolveChrome"/> and return its GL handle.
|
||||
/// The remaining args (type, underlayId, overlayId, effects) are ignored
|
||||
/// for the studio — a single-layer icon is sufficient for layout preview.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>This is what the task spec calls "v1 raw-resolve stub".</para>
|
||||
/// </summary>
|
||||
private static Func<ItemType, uint, uint, uint, uint, uint> MakeIconIds(RenderStack stack)
|
||||
=> (_, iconId, _, _, _) =>
|
||||
{
|
||||
if (iconId == 0u) return 0u;
|
||||
var (handle, _, _) = stack.ResolveChrome(iconId);
|
||||
return handle;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue