fix #234: port retail appraisal floaty and inscriptions

This commit is contained in:
Erik 2026-07-23 12:12:57 +02:00
parent 643cdfe66e
commit f1a7912160
23 changed files with 1310 additions and 106 deletions

View file

@ -8,6 +8,27 @@ namespace AcDream.Core.Net.Tests.Messages;
public sealed class AppraiseInfoParserTests
{
[Theory]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.IntStatsTable, 0x0001u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.BoolStatsTable, 0x0002u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.FloatStatsTable, 0x0004u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.StringStatsTable, 0x0008u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.SpellBook, 0x0010u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.WeaponProfile, 0x0020u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.HookProfile, 0x0040u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.ArmorProfile, 0x0080u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.CreatureProfile, 0x0100u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.ArmorEnchantmentBitfield, 0x0200u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.ResistEnchantmentBitfield, 0x0400u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.WeaponEnchantmentBitfield, 0x0800u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.DidStatsTable, 0x1000u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.Int64StatsTable, 0x2000u)]
[InlineData(AppraiseInfoParser.IdentifyResponseFlags.ArmorLevels, 0x4000u)]
public void IdentifyResponseFlags_MatchRetailWireValues(
AppraiseInfoParser.IdentifyResponseFlags flag,
uint wireValue)
=> Assert.Equal(wireValue, (uint)flag);
/// <summary>
/// Build an AppraiseInfo payload matching ACE's wire format. Starts
/// with (guid, flags, success) then per-flag tables.
@ -319,6 +340,27 @@ public sealed class AppraiseInfoParserTests
Assert.Equal(300u, c.Health);
}
[Fact]
public void TryParse_LiteralAceCreatureFlag_DoesNotDecodeAsWeapon()
{
using var ms = new MemoryStream();
using var bw = new BinaryWriter(ms);
bw.Write(0x50000001u);
bw.Write(0x0100u); // ACE IdentifyResponseFlags.CreatureProfile
bw.Write(1u);
bw.Write(0u);
bw.Write(300u);
bw.Write(400u);
AppraiseInfoParser.Parsed? parsed =
AppraiseInfoParser.TryParse(ms.ToArray());
Assert.NotNull(parsed);
Assert.NotNull(parsed.Value.CreatureProfile);
Assert.Null(parsed.Value.WeaponProfile);
Assert.Equal(300u, parsed.Value.CreatureProfile.Value.Health);
}
[Fact]
public void TryParse_ArmorEnchantmentBitfield_HighlightAndColor()
{

View file

@ -148,4 +148,42 @@ public sealed class InventoryActionsTests
Assert.Equal(0x0195u, BinaryPrimitives.ReadUInt32LittleEndian(b.AsSpan(8)));
Assert.Equal(0x500000C9u, BinaryPrimitives.ReadUInt32LittleEndian(b.AsSpan(12)));
}
[Fact]
public void BuildSetInscription_UsesRetailOpcodeGuidAndCp1252String16L()
{
byte[] body = InventoryActions.BuildSetInscription(
seq: 7,
itemGuid: 0x50000A01u,
inscription: "Café");
Assert.Equal(24, body.Length);
Assert.Equal(0xF7B1u,
BinaryPrimitives.ReadUInt32LittleEndian(body));
Assert.Equal(7u,
BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(4)));
Assert.Equal(0x00BFu,
BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(8)));
Assert.Equal(0x50000A01u,
BinaryPrimitives.ReadUInt32LittleEndian(body.AsSpan(12)));
Assert.Equal(4,
BinaryPrimitives.ReadUInt16LittleEndian(body.AsSpan(16)));
Assert.Equal(new byte[] { 0x43, 0x61, 0x66, 0xE9 },
body.AsSpan(18, 4).ToArray());
Assert.Equal(new byte[] { 0, 0 }, body.AsSpan(22, 2).ToArray());
}
[Fact]
public void BuildSetInscription_EmptyTextPacksAlignedClearRequest()
{
byte[] body = InventoryActions.BuildSetInscription(
seq: 1,
itemGuid: 0x50000A01u,
inscription: string.Empty);
Assert.Equal(20, body.Length);
Assert.Equal(0,
BinaryPrimitives.ReadUInt16LittleEndian(body.AsSpan(16)));
Assert.Equal(new byte[] { 0, 0 }, body.AsSpan(18, 2).ToArray());
}
}