diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index e05ecc23..709822ba 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -2039,24 +2039,6 @@ public sealed class GameWindow : IDisposable toolbarFrame.AddChild(toolbarRoot); _uiHost.Root.AddChild(toolbarFrame); - // [D.5.1 PROBE] Bottom-right geometry rect dump — temporary diagnostic. - // Localises the bottom-right mismatch reported by the user; remove once fixed. - // ScreenPosition walks Parent chain (UiElement.cs:54-63); Left/Top are parent-relative. - // IDs: root=0x10000191, backpack-btn=0x100001B1, backpack-drag=0x1000046C, - // last top slot=0x100001AF, last bottom slot=0x100006BF, - // row1 right-cap=0x100001B0, row2 right-cap=0x100006C0. - { - uint[] probeIds = { 0x10000191u, 0x100001B1u, 0x1000046Cu, 0x100001AFu, 0x100006BFu, 0x100001B0u, 0x100006C0u }; - foreach (var pid in probeIds) - { - var pe = toolbarLayout.FindElement(pid); - if (pe is not null) - Console.WriteLine($"[D.5.1 probe] 0x{pid:X8} ({pe.GetType().Name}): screen=({pe.ScreenPosition.X:F1},{pe.ScreenPosition.Y:F1}) left={pe.Left:F1} top={pe.Top:F1} w={pe.Width:F1} h={pe.Height:F1}"); - else - Console.WriteLine($"[D.5.1 probe] 0x{pid:X8}: not found in layout"); - } - } - Console.WriteLine("[D.5.1] retail toolbar window from LayoutDesc importer (0x21000016)."); } else Console.WriteLine("[D.5.1] toolbar: LayoutDesc 0x21000016 not found."); diff --git a/tests/AcDream.Core.Net.Tests/Messages/CreateObjectTests.cs b/tests/AcDream.Core.Net.Tests/Messages/CreateObjectTests.cs index b58c6fe3..ce9ea4a1 100644 --- a/tests/AcDream.Core.Net.Tests/Messages/CreateObjectTests.cs +++ b/tests/AcDream.Core.Net.Tests/Messages/CreateObjectTests.cs @@ -295,6 +295,43 @@ public sealed class CreateObjectTests Assert.Equal(0x06002222u, parsed!.Value.IconOverlayId); } + [Fact] + public void TryParse_HouseRestrictionsSkipped_ThenIconOverlayCaptured() + { + // Verifies that the variable-length RestrictionDB skip (weenieFlags bit + // 0x04000000) lands the cursor at the correct position so that + // IconOverlay (bit 0x40000000) immediately after it is still captured. + // + // Wire layout per ACE RestrictionDB (16 bytes, zero entries): + // Version(u32) + OpenStatus(u32) + MonarchId(u32) = 12 bytes + // count(u16) + numBuckets(u16) = 4 bytes + // entries: count(0) × 8 = 0 bytes + // total = 16 bytes + // + // Also exercises the IncludesSecondHeader / IconUnderlay path so that + // all three optional-tail branches that follow HouseOwner are covered + // in a single cursor sweep. + // + // weenieFlags: 0x04000000 (HouseRestrictions) | 0x40000000 (IconOverlay) + // objectDescriptionFlags: 0x04000000 (IncludesSecondHeader → weenieFlags2 present) + // weenieFlags2: 0x00000001 (IconUnderlay) + byte[] body = BuildMinimalCreateObjectWithWeenieHeader( + guid: 0x5000000Eu, + name: "HousePortal", + itemType: (uint)ItemType.Portal, + objectDescriptionFlags: 0x04000000u, // IncludesSecondHeader + weenieFlags: 0x04000000u | 0x40000000u, // HouseRestrictions + IconOverlay + weenieFlags2: 0x00000001u, // IconUnderlay + iconOverlayId: 0x3333u, // → 0x06003333 + iconUnderlayId: 0x4444u); // → 0x06004444 + + var parsed = CreateObject.TryParse(body); + + Assert.NotNull(parsed); + Assert.Equal(0x06003333u, parsed!.Value.IconOverlayId); + Assert.Equal(0x06004444u, parsed.Value.IconUnderlayId); + } + private static byte[] BuildMinimalCreateObjectWithWeenieHeader( uint guid, string name,