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
168
src/AcDream.App/Studio/SampleData.cs
Normal file
168
src/AcDream.App/Studio/SampleData.cs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
using AcDream.Core.Items;
|
||||
|
||||
namespace AcDream.App.Studio;
|
||||
|
||||
/// <summary>
|
||||
/// Static sample data for the UI Studio fixture provider.
|
||||
/// Provides a pre-built <see cref="ClientObjectTable"/> populated with a
|
||||
/// representative player, their main-pack items, side bags, and equipped gear,
|
||||
/// so the 2-D inventory / paperdoll panels render populated when previewed in
|
||||
/// the studio without a live game session.
|
||||
///
|
||||
/// Icon ids used (all real 0x06xxxxxx RenderSurface ids confirmed in the dats):
|
||||
/// Inventory empty-slot sprite : 0x06004D20
|
||||
/// Generic "misc" item : 0x060011D4 (icon_misc_underlay / fallback)
|
||||
/// Iron Sword (melee weapon) : 0x060011CBu (acclient default weapon underlay)
|
||||
/// Leather Breastplate (armor) : 0x060011CFu (acclient default armor underlay)
|
||||
/// Leather Gloves : 0x060011F3u (acclient default clothing underlay)
|
||||
/// Steel Ring : 0x060011D5u (acclient default jewelry underlay)
|
||||
/// Healing Kit : 0x060011D4u (generic misc fallback)
|
||||
/// Spell components : 0x060011D4u (generic misc fallback)
|
||||
/// Side-bag 1 (Container) : 0x06004D20u
|
||||
/// Side-bag 2 (Container) : 0x06004D20u
|
||||
/// Equipped helm (HeadWear) : 0x060011F3u
|
||||
/// Equipped chest armor : 0x060011CFu
|
||||
/// Equipped melee weapon : 0x060011CBu
|
||||
///
|
||||
/// These are the icon *base* RenderSurface ids — the same ids GameWindow passes
|
||||
/// as `iconId` into the iconIds lambda. FixtureProvider resolves them via
|
||||
/// <see cref="Rendering.RenderStack.ResolveChrome"/> and returns the raw GL handle.
|
||||
/// </summary>
|
||||
public static class SampleData
|
||||
{
|
||||
// ── Guids ────────────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>Fake server guid for the studio's synthetic player.</summary>
|
||||
public const uint PlayerGuid = 0x50000001u;
|
||||
|
||||
// Items in main pack (slots 0–5).
|
||||
private const uint SwordGuid = 0x50000010u;
|
||||
private const uint ChestGuid = 0x50000011u;
|
||||
private const uint GlovesGuid = 0x50000012u;
|
||||
private const uint RingGuid = 0x50000013u;
|
||||
private const uint HealKitGuid = 0x50000014u;
|
||||
private const uint CompGuid = 0x50000015u;
|
||||
|
||||
// Side bags (also in main pack, ContainerId = PlayerGuid; slots 6 & 7).
|
||||
private const uint Bag1Guid = 0x50000020u;
|
||||
private const uint Bag2Guid = 0x50000021u;
|
||||
|
||||
// Equipped items (ContainerId = PlayerGuid, CurrentlyEquippedLocation set).
|
||||
private const uint HelmGuid = 0x50000030u;
|
||||
private const uint ChestEqGuid = 0x50000031u;
|
||||
private const uint WeaponEqGuid = 0x50000032u;
|
||||
|
||||
// ── Icon ids (0x06xxxxxx RenderSurface dat ids) ───────────────────────────
|
||||
|
||||
// These are the same underlay/fallback icon ids the IconComposer tests pin.
|
||||
private const uint IconWeapon = 0x060011CBu; // weapon underlay
|
||||
private const uint IconArmor = 0x060011CFu; // armor underlay
|
||||
private const uint IconClothing = 0x060011F3u; // clothing underlay
|
||||
private const uint IconJewelry = 0x060011D5u; // jewelry underlay
|
||||
private const uint IconMisc = 0x060011D4u; // misc / fallback underlay
|
||||
|
||||
// ── Public API ──────────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Build a fresh <see cref="ClientObjectTable"/> populated with the
|
||||
/// studio's sample player + a realistic inventory snapshot.
|
||||
/// The table is owned by the caller and should be kept alive for the
|
||||
/// window's lifetime.
|
||||
/// </summary>
|
||||
public static ClientObjectTable BuildObjectTable()
|
||||
{
|
||||
var t = new ClientObjectTable();
|
||||
|
||||
// ── Player object ─────────────────────────────────────────────────
|
||||
t.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = PlayerGuid,
|
||||
Name = "Studio Player",
|
||||
Type = ItemType.Creature,
|
||||
ItemsCapacity = 102,
|
||||
ContainersCapacity = 7,
|
||||
});
|
||||
|
||||
// ── Loose items in main pack (slots 0–5) ──────────────────────────
|
||||
|
||||
AddItem(t, SwordGuid, ItemType.MeleeWeapon, IconWeapon, "Iron Sword", PlayerGuid, 0, burden: 60);
|
||||
AddItem(t, ChestGuid, ItemType.Armor, IconArmor, "Leather Breastplate", PlayerGuid, 1, burden: 200);
|
||||
AddItem(t, GlovesGuid, ItemType.Clothing, IconClothing, "Leather Gloves", PlayerGuid, 2, burden: 50);
|
||||
AddItem(t, RingGuid, ItemType.Jewelry, IconJewelry, "Steel Ring", PlayerGuid, 3, burden: 10);
|
||||
AddItem(t, HealKitGuid, ItemType.Misc, IconMisc, "Healing Kit", PlayerGuid, 4, burden: 30);
|
||||
AddItem(t, CompGuid, ItemType.SpellComponents, IconMisc, "Spell Comps", PlayerGuid, 5, burden: 25, stackSize: 50, stackMax: 100);
|
||||
|
||||
// ── Side bags (Container items in main pack, slots 6 & 7) ─────────
|
||||
|
||||
AddItem(t, Bag1Guid, ItemType.Container, IconMisc, "Small Pack 1",
|
||||
containerId: PlayerGuid, slot: 6, burden: 20, itemsCapacity: 24);
|
||||
AddItem(t, Bag2Guid, ItemType.Container, IconMisc, "Small Pack 2",
|
||||
containerId: PlayerGuid, slot: 7, burden: 20, itemsCapacity: 24);
|
||||
|
||||
// ── Equipped items (ContainerId = PlayerGuid, CurrentlyEquippedLocation set) ──
|
||||
|
||||
AddEquipped(t, HelmGuid, ItemType.Armor, IconClothing, "Tin Helm", EquipMask.HeadWear);
|
||||
AddEquipped(t, ChestEqGuid, ItemType.Armor, IconArmor, "Chain Coat", EquipMask.ChestArmor);
|
||||
AddEquipped(t, WeaponEqGuid, ItemType.MeleeWeapon, IconWeapon, "Wooden Sword", EquipMask.MeleeWeapon);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
// ── Sample vital constants (used by FixtureProvider) ────────────────────
|
||||
|
||||
public const float HealthPct = 0.8f;
|
||||
public const float StaminaPct = 0.6f;
|
||||
public const float ManaPct = 0.9f;
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
private static void AddItem(
|
||||
ClientObjectTable t,
|
||||
uint guid,
|
||||
ItemType type,
|
||||
uint iconId,
|
||||
string name,
|
||||
uint containerId,
|
||||
int slot,
|
||||
int burden = 0,
|
||||
int stackSize = 1,
|
||||
int stackMax = 1,
|
||||
int itemsCapacity = 0)
|
||||
{
|
||||
t.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = guid,
|
||||
Name = name,
|
||||
Type = type,
|
||||
IconId = iconId,
|
||||
Burden = burden,
|
||||
StackSize = stackSize,
|
||||
StackSizeMax = stackMax,
|
||||
ItemsCapacity = itemsCapacity,
|
||||
});
|
||||
t.MoveItem(guid, containerId, slot);
|
||||
}
|
||||
|
||||
private static void AddEquipped(
|
||||
ClientObjectTable t,
|
||||
uint guid,
|
||||
ItemType type,
|
||||
uint iconId,
|
||||
string name,
|
||||
EquipMask equipMask)
|
||||
{
|
||||
t.AddOrUpdate(new ClientObject
|
||||
{
|
||||
ObjectId = guid,
|
||||
Name = name,
|
||||
Type = type,
|
||||
IconId = iconId,
|
||||
ValidLocations = equipMask,
|
||||
CurrentlyEquippedLocation = equipMask,
|
||||
ContainerId = PlayerGuid,
|
||||
});
|
||||
// Update the equip location on the object via MoveItem (sets ContainerId +
|
||||
// CurrentlyEquippedLocation via the equip overload).
|
||||
t.MoveItem(guid, PlayerGuid, newSlot: -1, newEquipLocation: equipMask);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue