Build against plugin API 0.1.19-mm.1; item header words from the host

The contract now reports each object's description header, so the item
record carries the words the original's framework filed from it: the weenie
and second header flags, the physics description flags, the setup id, the
scale key (0.0 whenever a scale was sent, as recorded), the hook type, the
parent and parent location, and the framework's own summary word (key
218103831: stackable, has a position, lockable, inscribable, usable,
container), derived from the header by a rule that matches all 2,220 recorded
items carrying both words. With the header flags known, key presence follows
the header exactly instead of guessing from non-zero values: a recorded
Pyreal Mote now rebuilds key for key.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-25 12:58:43 +02:00
parent 0af4efb6b6
commit 50a173ef25
5 changed files with 121 additions and 5 deletions

View file

@ -0,0 +1,69 @@
using AcDream.Plugin.Abstractions;
using OpenAC.MosswartMassacre.Inventory;
namespace OpenAC.MosswartMassacre.Tests.Inventory;
/// <summary>
/// Items exactly as the original recorded them from a live game (the dumps in
/// the Mag-Plugins repository), rebuilt from the header words the host now
/// reports: the key tables must come out the same, value for value.
/// </summary>
public sealed class RecordedItemTests
{
[Fact]
public void A_recorded_pyreal_mote_rebuilds_key_for_key()
{
// Barris.json, the first item: a Pyreal Mote in a side pack, never
// appraised. Its IntValues and DoubleValues as recorded:
var expectedInts = new Dictionary<int, int>
{
[218103847] = 137345, [218103830] = 33556406, [218103832] = 271151128,
[19] = 10, [218103808] = 6353, [218103809] = 7208, [218103834] = 128,
[218103843] = 524296, [218103835] = 18, [218103826] = 128, [218103831] = 17,
[218103814] = 1, [218103815] = 1, [5] = 1, [218103810] = 1342431769,
[218103822] = 0, [218103828] = 2,
};
var expectedDoubles = new Dictionary<int, double> { [167772170] = 0.0 };
var item = new PluginInventoryItem(
unchecked((uint)-2126483018), 6353u, "Pyreal Mote", 128u, 1342431769u, 0u, 0u, 0u,
524296u, 128u, 18u, 1, 0, 0, 0u, 0, 0, 0u, false, 0d, 0, 0, 0, 0d, 0, 0, 0)
{
ObjectClass = PluginObjectClass.Misc,
IconId = 0x06000000u + 7208u,
MaximumStackSize = 1,
Burden = 1,
Value = 10,
Header = new PluginObjectHeader(
WeenieHeaderFlags: 271151128u,
WeenieHeaderFlags2: null,
PhysicsDescriptionFlags: 137345u,
PhysicsState: null,
ObjectDescriptionFlags: 18u,
SetupId: 33556406u,
Scale: 1.0f,
HookType: 2u,
ParentObjectId: null,
ParentLocation: null,
UseRadius: null),
};
MyWorldObject record = DecalItemBuilder.Create(new ItemSource(
item, null, false, 0, HostItemHeaderSource.Instance.Read(item)));
Assert.Equal(expectedInts.OrderBy(p => p.Key), record.IntValues.OrderBy(p => p.Key));
Assert.Equal(expectedDoubles.OrderBy(p => p.Key), record.DoubleValues.OrderBy(p => p.Key));
Assert.Equal("Pyreal Mote", record.StringValues[1]);
}
[Theory]
// Values of key 218103831 recorded for items, with their header words.
[InlineData(0x1000u, 0u, 0u, 0u, 0x01u)] // a stack
[InlineData(0u, 0x8000u, 0u, 0u, 0x02u)] // on the ground
[InlineData(0u, 0u, 0x20000u, 0u, 0x04u)] // lockable
[InlineData(0u, 0u, 0u, 0x2u, 0x10u)] // inscribable
[InlineData(0x800u, 0u, 0u, 0u, 0x20u)] // uses
[InlineData(0x2u, 0u, 0u, 0x12u, 0x90u)] // a pack
public void The_frameworks_summary_word(uint weenie, uint physics, uint itemType, uint description, uint expected) =>
Assert.Equal(expected, HostItemHeaderSource.FrameworkFlags(weenie, physics, itemType, description));
}