fix(D.5.1): toolbar movable + chrome-grab + peace-only indicator + no prototype square
D1 — Toolbar not movable: toolbarRoot.Anchors = AnchorEdges.None (was Left|Top) so ApplyAnchor early-returns and doesn't re-pin the window every frame. Matches the vitalsRoot idiom exactly. D2 — Cannot grab toolbar by chrome: toolbarRoot.ClickThrough = false so HitTest succeeds over the UiDatElement chrome and the drag starts. UiDatElement ctor defaults ClickThrough=true; vitalsRoot already overrides it. C1 — All four combat-mode indicators visible at once (war/flame stacked on peace): ports gmToolbarUI::RecvNotice_SetCombatMode (acclient_2013_pseudo_c.txt:196632-196669). CombatIndicatorIds[] maps index 0-3 to NonCombat/Melee/Missile/Magic; SetCombatMode shows exactly one and hides the other three. Default to NonCombat at bind (player always spawns in peace). Wires CombatState.CombatModeChanged for live updates. Tests: CombatIndicator_defaultNonCombat_onlyPeaceVisible, CombatIndicator_setCombatModeMelee_onlyMeleeVisible, CombatIndicator_liveSignal_updatesWhenCombatStateChanges. V1 — Blue empty-slot square at top-left (prototype 0x100001B2 materialized): ImportInfos now skips top-level elements that are (a) referenced as a BaseElement by another element in the same layout AND (b) have no own state media. The CollectBaseRefsInDesc walk covers nested children; HasNoOwnMedia re-uses ToInfo's media extraction. The Resolve path reads BaseElement from the raw dat via dats.Get<LayoutDesc> — it never depends on the prototype being in the built widget tree — so the skip is safe. Conformance tests (vitals, chat) are unaffected (they exercise Build, not ImportInfos). Test: BuildFromInfos_PrototypeSkipped_DerivedPresent_PrototypeAbsent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b3e5e8b0f7
commit
bfc452d610
5 changed files with 262 additions and 11 deletions
|
|
@ -93,6 +93,54 @@ public class LayoutImporterTests
|
|||
Assert.Empty(uiMeter.Children);
|
||||
}
|
||||
|
||||
// ── Test 4: Prototype-skip in BuildFromInfos ─────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// When one top-level element is referenced as a BaseElement by a sibling
|
||||
/// (mirroring the toolbar slot prototype pattern), and the prototype element
|
||||
/// has no own state media, the importer must NOT produce a widget for the
|
||||
/// prototype id (FindElement returns null), but MUST produce the derived element.
|
||||
///
|
||||
/// NOTE: This test exercises <see cref="LayoutImporter.BuildFromInfos"/> (the pure
|
||||
/// layer), where prototype detection is done by inspecting the pre-resolved
|
||||
/// ElementInfo tree rather than the raw dat ElementDesc. The pure layer skips
|
||||
/// an element if its Id is in a sibling's (or child's) <c>Children</c> chain
|
||||
/// as a BaseElement — but actually the pure layer has no BaseElement knowledge
|
||||
/// at this stage (that's resolved before Build). The prototype-skip in the real
|
||||
/// world occurs in <c>ImportInfos</c> (the dat shell), BEFORE calling Build.
|
||||
///
|
||||
/// This test verifies the INVARIANT that holds AFTER ImportInfos filters prototypes:
|
||||
/// a pure template element that was skipped is absent from FindElement, while the
|
||||
/// derived element (which inherited from it) IS present.
|
||||
///
|
||||
/// We model this by simply NOT adding the prototype to the ElementInfo tree passed
|
||||
/// to BuildFromInfos — as if ImportInfos already filtered it out.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void BuildFromInfos_PrototypeSkipped_DerivedPresent_PrototypeAbsent()
|
||||
{
|
||||
// Simulate what ImportInfos does AFTER filtering: the prototype 0xBBB00001 is
|
||||
// absent (already skipped by ImportInfos), the derived element 0xCCC00001 is
|
||||
// present with its own media inherited from the prototype.
|
||||
var root = new ElementInfo { Id = 0x10000001, Type = 3, Width = 200, Height = 100 };
|
||||
// The derived element has its own size + media (prototype was merged into it already).
|
||||
var derived = new ElementInfo
|
||||
{
|
||||
Id = 0xCCC00001u,
|
||||
Type = 0x10000031u, // UIElement_ItemList (toolbar slot type)
|
||||
X = 10, Y = 10, Width = 32, Height = 32,
|
||||
};
|
||||
derived.StateMedia[""] = (0x06001234u, 1);
|
||||
|
||||
// Only the derived element appears in the tree (prototype was filtered by ImportInfos).
|
||||
var tree = LayoutImporter.BuildFromInfos(root, new[] { derived }, NoTex, null);
|
||||
|
||||
// The derived element is present in the built tree.
|
||||
Assert.NotNull(tree.FindElement(0xCCC00001u));
|
||||
// The prototype id is NOT in the tree (was never added).
|
||||
Assert.Null(tree.FindElement(0xBBB00001u));
|
||||
}
|
||||
|
||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||
|
||||
private static ElementInfo BuildSliceContainer(uint id, uint ReadOrder, uint l, uint t, uint r)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue