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:
parent
6b1ae4fb76
commit
643cdfe66e
24 changed files with 17132 additions and 40 deletions
|
|
@ -34,7 +34,7 @@ namespace AcDream.Core.Net.Messages;
|
|||
/// if (flags & StringStatsTable) packedTable<u32 key, string16L value>
|
||||
/// if (flags & DidStatsTable) packedTable<u32 key, u32 value>
|
||||
/// if (flags & SpellBook) u32 count, u32[count] spellIds
|
||||
/// ...armor/creature/weapon/hook profile blobs follow (deferred)
|
||||
/// ...armor/creature/weapon/hook profile blobs follow
|
||||
/// </code>
|
||||
/// </para>
|
||||
///
|
||||
|
|
@ -48,10 +48,9 @@ namespace AcDream.Core.Net.Messages;
|
|||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// Returns a fully-populated <see cref="PropertyBundle"/>. Profile
|
||||
/// blobs (ArmorProfile / CreatureProfile / WeaponProfile / HookProfile)
|
||||
/// are recognised via the flag bits but not yet deserialized — the
|
||||
/// parser seeks past them to keep the flag walk aligned.
|
||||
/// Returns the complete gated appraisal payload. A malformed gated field
|
||||
/// rejects the packet rather than returning a partial profile whose cursor
|
||||
/// could be misaligned for every later field.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static class AppraiseInfoParser
|
||||
|
|
@ -107,6 +106,12 @@ public static class AppraiseInfoParser
|
|||
double WeaponOffense,
|
||||
uint MaxVelocityEstimated);
|
||||
|
||||
/// <summary>Hook-container item metadata serialized as three consecutive u32 values.</summary>
|
||||
public readonly record struct HookProfile(
|
||||
uint Flags,
|
||||
uint ValidLocations,
|
||||
uint AmmoType);
|
||||
|
||||
/// <summary>Creature vitals + (optionally) attributes from a CreatureProfile blob.</summary>
|
||||
public readonly record struct CreatureProfile(
|
||||
uint Flags,
|
||||
|
|
@ -134,6 +139,7 @@ public static class AppraiseInfoParser
|
|||
ArmorProfile? ArmorProfile,
|
||||
CreatureProfile? CreatureProfile,
|
||||
WeaponProfile? WeaponProfile,
|
||||
HookProfile? HookProfile,
|
||||
ArmorLevel? ArmorLevels,
|
||||
(ushort Highlight, ushort Color)? ArmorEnchantments,
|
||||
(ushort Highlight, ushort Color)? WeaponEnchantments,
|
||||
|
|
@ -160,6 +166,7 @@ public static class AppraiseInfoParser
|
|||
ArmorProfile? armor = null;
|
||||
CreatureProfile? creature = null;
|
||||
WeaponProfile? weapon = null;
|
||||
HookProfile? hook = null;
|
||||
ArmorLevel? levels = null;
|
||||
(ushort H, ushort C)? armorEnc = null, weaponEnc = null, resistEnc = null;
|
||||
|
||||
|
|
@ -187,7 +194,8 @@ public static class AppraiseInfoParser
|
|||
creature = ReadCreatureProfile(payload, ref pos);
|
||||
if (flags.HasFlag(IdentifyResponseFlags.WeaponProfile))
|
||||
weapon = ReadWeaponProfile(payload, ref pos);
|
||||
// HookProfile (0x200) — not deserialized; would need HookProfile struct port.
|
||||
if (flags.HasFlag(IdentifyResponseFlags.HookProfile))
|
||||
hook = ReadHookProfile(payload, ref pos);
|
||||
if (flags.HasFlag(IdentifyResponseFlags.ArmorEnchantmentBitfield))
|
||||
armorEnc = ReadEnchantmentBitfield(payload, ref pos);
|
||||
if (flags.HasFlag(IdentifyResponseFlags.WeaponEnchantmentBitfield))
|
||||
|
|
@ -199,12 +207,12 @@ public static class AppraiseInfoParser
|
|||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
// Malformed table — return what we got so far.
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Parsed(
|
||||
guid, flags, success != 0, bundle, spellBook,
|
||||
armor, creature, weapon, levels,
|
||||
armor, creature, weapon, hook, levels,
|
||||
armorEnc, weaponEnc, resistEnc);
|
||||
}
|
||||
|
||||
|
|
@ -252,6 +260,12 @@ public static class AppraiseInfoParser
|
|||
MaxVelocityEstimated: ReadU32(src, ref pos));
|
||||
}
|
||||
|
||||
private static HookProfile ReadHookProfile(ReadOnlySpan<byte> src, ref int pos)
|
||||
=> new(
|
||||
Flags: ReadU32(src, ref pos),
|
||||
ValidLocations: ReadU32(src, ref pos),
|
||||
AmmoType: ReadU32(src, ref pos));
|
||||
|
||||
private static CreatureProfile ReadCreatureProfile(ReadOnlySpan<byte> src, ref int pos)
|
||||
{
|
||||
uint flags = ReadU32(src, ref pos);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue