feat(ui): port retail appraisal panel

Preserve retail's one-pending-appraisal busy lifetime, parse the complete gated response, and mount the authored examination layout in the shared main-panel host. Keep known 3D preview and inscription-write gaps explicit in AP-110.
This commit is contained in:
Erik 2026-07-23 11:34:08 +02:00
parent 6b1ae4fb76
commit 643cdfe66e
24 changed files with 17132 additions and 40 deletions

View file

@ -183,6 +183,19 @@ public sealed class AppraiseInfoParserTests
Assert.Null(AppraiseInfoParser.TryParse(new byte[4]));
}
[Fact]
public void TryParse_TruncatedGatedField_RejectsEntirePacket()
{
using var ms = new MemoryStream();
using var bw = new BinaryWriter(ms);
bw.Write(0x50000001u);
bw.Write((uint)AppraiseInfoParser.IdentifyResponseFlags.HookProfile);
bw.Write(1u);
bw.Write(0x3u);
Assert.Null(AppraiseInfoParser.TryParse(ms.ToArray()));
}
// ── Profile blobs ────────────────────────────────────────────────────────
[Fact]
@ -322,4 +335,31 @@ public sealed class AppraiseInfoParserTests
Assert.Equal((ushort)0x00FF, parsed.Value.ArmorEnchantments!.Value.Highlight);
Assert.Equal((ushort)0x0042, parsed.Value.ArmorEnchantments.Value.Color);
}
[Fact]
public void TryParse_HookProfile_PreservesAlignmentForFollowingFields()
{
using var ms = new MemoryStream();
using var bw = new BinaryWriter(ms);
bw.Write(0x50000001u);
bw.Write((uint)(
AppraiseInfoParser.IdentifyResponseFlags.HookProfile
| AppraiseInfoParser.IdentifyResponseFlags.ArmorEnchantmentBitfield));
bw.Write(1u);
bw.Write(0x0000000Bu);
bw.Write(0x00100000u);
bw.Write(0x00000004u);
bw.Write((ushort)0x1234);
bw.Write((ushort)0x5678);
var parsed = AppraiseInfoParser.TryParse(ms.ToArray());
Assert.NotNull(parsed);
Assert.Equal(
new AppraiseInfoParser.HookProfile(0xBu, 0x00100000u, 4u),
parsed.Value.HookProfile);
Assert.Equal(
((ushort)0x1234, (ushort)0x5678),
parsed.Value.ArmorEnchantments);
}
}