acdream/tests/AcDream.App.Tests/UI/Layout/FaPanelSlotProbeTests.cs
Erik 1226f289f3 research: Campaign FA lanes A-D + the U2 slot-table probe (social panel found)
Four Opus research lanes for the Fellowship & Allegiance campaign:
panel structure, fellowship wire (two BN zero-folds broken by byte
decode: IsFull >= 9, the x87 XP-share table capping at 2.8x), allegiance
wire (27+5 messages binary-verified; tree assembly discard/reversal
rules; ACE zeroed-field caveats), and the acdream seams audit (H.2
scaffolding inventory, J-owner recommendation, AD-78 dimmed-row
inventory, bot-gate requirements).

Coordinator U2 closure (FaPanelSlotProbeTests, live DATs): Fellowship
and Allegiance are two of FOUR pages of ONE tabbed social panel — slot
0x1000018F, panel id 12, Type-8 host — alongside gmFriendsUI and
gmSquelchUI; lane A's separate-siblings mounting call is corrected in
its addendum, and the full 16-slot dump closes every unidentified
RetailPanelCatalog entry (Abuse/Book/LinkStatus/MiniGame/UA/Vitae/
Map+House/Journal).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 23:42:19 +02:00

95 lines
4 KiB
C#

using System.IO;
using AcDream.App.UI.Layout;
using DatReaderWriter;
using DatReaderWriter.Options;
namespace AcDream.App.Tests.UI.Layout;
/// <summary>
/// Campaign FA lane-A unknown U2 (docs/research/2026-08-11-fa-panel-structure.md
/// §8): which of the 16 gmPanelUI page-stack slots host the Fellowship and
/// Allegiance panels, and each slot's authored P0x10000029 panel id. Dumps the
/// full 16-row table against the live DATs — closing U2 (and the ten
/// unidentified RetailPanelCatalog entries) in one pass. Signature elements
/// identify the two FA slots definitively: 0x1000026F (fellowship name field)
/// and 0x10000263 (swear-allegiance button). Env-gated like the other probes.
/// </summary>
public sealed class FaPanelSlotProbeTests
{
[Fact]
public void ProbePanelSlotTable()
{
if (Environment.GetEnvironmentVariable("ACDREAM_PROBE_LIVE_MOUNT") != "1")
return;
var datDir = Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR")
?? Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"Documents",
"Asheron's Call");
using var dats = new DatCollection(datDir, DatAccessType.Read);
// The 16 authored slot ids, in gmPanelUI::SetupChildren call order
// (lane-A doc §2.2), plus the conspicuously-absent 0x10000186.
foreach (uint slotId in new[]
{
0x1000018Bu, 0x1000018Fu, 0x1000018Eu, 0x10000559u,
0x1000018Cu, 0x10000182u, 0x1000018Du, 0x10000190u,
0x10000184u, 0x10000185u, 0x10000181u, 0x10000189u,
0x10000183u, 0x1000018Au, 0x10000187u, 0x10000188u,
0x10000186u,
})
{
ElementInfo? slot = LayoutImporter.ImportInfos(dats, 0x2100006Eu, slotId);
if (slot is null)
{
Console.WriteLine($"[faslot] 0x{slotId:X8} -> IMPORT NULL");
continue;
}
string panelId = slot.TryGetEffectiveProperty(0x10000029u, out var p)
? $"{p.UnsignedValue} (kind={p.Kind})"
: "ABSENT";
bool hasFellowshipName = FindInfo(slot, 0x1000026Fu);
// Allegiance signature set (lane A/C ids): swear 0x10000263,
// break 0x10000264, kick 0x10000265, row texts 0x10000268/69,
// and the doubled 0x10000492 monarch/patron child.
bool hasAllegiance = FindInfo(slot, 0x10000263u) || FindInfo(slot, 0x10000264u)
|| FindInfo(slot, 0x10000265u) || FindInfo(slot, 0x10000268u)
|| FindInfo(slot, 0x10000269u) || FindInfo(slot, 0x10000492u);
string family = hasFellowshipName ? " <= FELLOWSHIP"
: hasAllegiance ? " <= ALLEGIANCE"
: string.Empty;
Console.WriteLine(
$"[faslot] 0x{slotId:X8} panelId={panelId} type={slot.Type} "
+ $"({slot.X},{slot.Y} {slot.Width}x{slot.Height}) "
+ $"children={slot.Children.Count}{family}");
// The unidentified slots: dump two levels of child ids so the
// allegiance panel can be identified by SHAPE if its recovered
// element ids are absent from the base-merge.
bool unidentified = slotId is 0x1000018Fu;
if (unidentified)
{
foreach (ElementInfo c in slot.Children)
{
Console.WriteLine(
$"[faslot] child 0x{c.Id:X8} type={c.Type} ({c.X},{c.Y} {c.Width}x{c.Height}) kids={c.Children.Count}");
foreach (ElementInfo g in c.Children)
Console.WriteLine(
$"[faslot] g 0x{g.Id:X8} type={g.Type} ({g.X},{g.Y} {g.Width}x{g.Height})");
}
}
}
}
private static bool FindInfo(ElementInfo info, uint id)
{
if (info.Id == id) return true;
foreach (ElementInfo c in info.Children)
if (FindInfo(c, id)) return true;
return false;
}
}