fix(vtank): slice 7 round D item 1 — Advanced Options category names

Owner live report 2026-09-07: "Some Hex numbers with green button to
the right. What is that?" — the Advanced Options popup's category
filter checklist showed raw bitmask hex ("0x1", "0x2", ...) instead of
VTank's real category names (Misc, Recharge, MeleeCombat, SpellCombat,
Ranges, Navigation, Buffing, Crafting, Looting).

This worktree has no refs/vtank/ checkout, so VTank's own name/enum
string literal for each bit isn't directly readable. Derived the
mapping instead from real data already in the embedded .usd: for each
category name, docs/research/vtank-kb/01-settings-and-profiles.md §2
was searched for a setting whose Category column names EXACTLY that
one category (no `|` combination) — e.g. row 45 RandomHelperBuffs is
pure "Misc", row 18 AttackDistance is pure "Ranges" — then that
setting's own recorded bitmask was read back from
VtankDefaultSettingsDatabase.SettingCategoryBitmasks (never a typed-in
hex literal), so the mapping tracks the shipped database instead of
silently drifting from it. All 9 of VtankOptionCatalog.CategoryBits
resolve to a real name this way (VtankOptionCatalog.
CategoryNamesByBit), in VTank's own ascending-bit order.

Mutation shown to fail: reverting AdvancedOptionCategoryNames to the
old `$"0x{bit:X}"` projection failed the new
AdvancedOptionCategoryNamesShowRealNamesNotHexBitmasks test with
["0x1", "0x2", ...] instead of ["Misc", "Recharge", ...]; restored and
confirmed green.

Verified: dotnet build AcDream.slnx -c Release green; MossTank suite
679/679 (678 -> 679); App markup/plugin filter 242/242 (unchanged).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-09-07 16:21:57 +02:00
parent 4ba0a557f6
commit ebe670adf5
3 changed files with 84 additions and 7 deletions

View file

@ -501,16 +501,23 @@ internal sealed partial class MossTankPanel
// with a clVal VALUE column, and filters both through lFilterList — a
// category checklist keyed by SettingsCategories' own per-setting
// bitmask (VtankDefaultSettingsDatabase.SettingCategoryBitmasks, 136
// rows straight from the embedded .usd). This worktree has no
// refs/vtank/ checkout, so VTank's own category NAME strings aren't
// available anywhere in this repo — the filter groups are labeled by
// their raw bit value ("0x04" etc.) instead of a guessed name; a
// setting with no recorded bitmask always shows regardless of filter
// state (never silently hidden by a filter that doesn't apply to it).
// rows straight from the embedded .usd). Round D (owner live report
// 2026-09-07: "Some Hex numbers with green button to the right. What
// is that?") replaced the raw bit-value labels ("0x04" etc.) with the
// real category NAMES (Misc, Recharge, MeleeCombat, SpellCombat,
// Ranges, Navigation, Buffing, Crafting, Looting) — see
// VtankOptionCatalog.CategoryNamesByBit for how each name is derived
// without a refs/vtank/ checkout. A setting with no recorded bitmask
// always shows regardless of filter state (never silently hidden by a
// filter that doesn't apply to it).
public IReadOnlyList<string> AdvancedOptionNames => _advancedOptionNames;
public IReadOnlyList<string> AdvancedOptionValueColumn => _advancedOptionValueColumn;
public IReadOnlyList<string> AdvancedOptionCategoryNames { get; } =
VtankOptionCatalog.CategoryBits.Select(bit => $"0x{bit:X}").ToArray();
VtankOptionCatalog.CategoryBits
.Select(bit => VtankOptionCatalog.CategoryNamesByBit.TryGetValue(bit, out string? name)
? name
: $"0x{bit:X}")
.ToArray();
public IReadOnlyList<bool> AdvancedOptionCategoryEnabled => _advancedOptionCategoryEnabledView;
// Fix round B item 15's own build-over-real-files test caught this:
// <list> markup REQUIRES a "selected" int binding (MarkupDocument.

View file

@ -404,6 +404,52 @@ internal static class VtankOptionCatalog
.Order()
.ToArray();
/// <summary>
/// VTank's own <c>lFilterList</c> checklist NAMES (owner live report
/// 2026-09-07: the popup showed raw bitmask hex — "0x1", "0x2" — instead
/// of category names). This worktree has no <c>refs/vtank/</c> checkout
/// to read VTank's own name/enum string literal for each bit directly,
/// so each name is instead anchored to a real setting whose Category
/// column in docs/research/vtank-kb/01-settings-and-profiles.md §2
/// names EXACTLY ONE category (no <c>|</c> combination), then read back
/// THAT setting's own recorded bitmask from the embedded .usd
/// (<see cref="VtankDefaultSettingsDatabase.SettingCategoryBitmasks"/>)
/// — never a typed-in hex literal, so the mapping cannot silently drift
/// from what the shipped database actually encodes. Anchors used (KB §2
/// row, single-category setting, resulting bit): row 45
/// RandomHelperBuffs→Misc(1), row 8 Recharge-Norm-HitP→Recharge(2), row
/// 31 DefaultMeleeAttackHeight→MeleeCombat(4), row 5
/// SpellDiffExcessThreshold-Hunt→SpellCombat(8), row 18
/// AttackDistance→Ranges(16), row 2 EnableNav→Navigation(32), row 3
/// EnableBuffing→Buffing(64), row 7
/// ArrowheadFletchDiffExcessThreshold→Crafting(128), row 1
/// EnableLooting→Looting(256) — all 9 of <see cref="CategoryBits"/>.
/// </summary>
internal static readonly IReadOnlyDictionary<int, string> CategoryNamesByBit =
BuildCategoryNamesByBit();
private static IReadOnlyDictionary<int, string> BuildCategoryNamesByBit()
{
IReadOnlyDictionary<string, int> bitmasks = VtankDefaultSettingsDatabase.SettingCategoryBitmasks;
(string Setting, string Category)[] anchors =
[
("RandomHelperBuffs", "Misc"),
("Recharge-Norm-HitP", "Recharge"),
("DefaultMeleeAttackHeight", "MeleeCombat"),
("SpellDiffExcessThreshold-Hunt", "SpellCombat"),
("AttackDistance", "Ranges"),
("EnableNav", "Navigation"),
("EnableBuffing", "Buffing"),
("ArrowheadFletchDiffExcessThreshold", "Crafting"),
("EnableLooting", "Looting"),
];
var map = new Dictionary<int, string>();
foreach ((string setting, string category) in anchors)
if (bitmasks.TryGetValue(setting, out int bit))
map[bit] = category;
return map;
}
private static IEnumerable<int> DecomposeBits(int mask)
{
for (int bit = 1; bit != 0 && bit <= mask; bit <<= 1)