using System.IO; using System.Linq; using AcDream.App.UI; using AcDream.App.UI.Layout; using AcDream.Content; using DatReaderWriter; using DatReaderWriter.DBObjs; using DatReaderWriter.Options; namespace AcDream.App.Tests.UI.Layout; /// /// #408 client-wide blast-radius gate for DAT property 0x3B (Invisible). /// Retail applies the property in UIElement::OnSetAttribute for every imported /// element. Enumerate every installed LayoutDesc, then prove every corresponding /// widget which survives importer child-consumption starts hidden. /// [Trait("Lane", "InstalledDat")] public sealed class LayoutImporterInvisibleSweepTests { private static string DatDirectory => System.Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR") ?? Path.Combine( System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile), "Documents", "Asheron's Call"); private readonly record struct Finding(uint LayoutId, uint ElementId); [InstalledDatFact] public void EveryAuthoredInvisibleWidget_StartsHiddenAcrossAllLayouts() { using var dats = new DatCollection(DatDirectory, DatAccessType.Read); var authored = new List(); var built = new List(); var incorrectlyVisible = new List(); foreach (uint layoutId in dats.GetAllIdsOfType().OrderBy(static id => id)) { ElementInfo? tree = LayoutImporter.ImportInfos(dats, layoutId); if (tree is null) continue; CollectAuthored(layoutId, tree, authored); ImportedLayout layout = LayoutImporter.Build( tree, _ => (0u, 0, 0), datFont: null, sourceLayoutDid: layoutId); CollectBuilt(layoutId, layout.Root, built, incorrectlyVisible); } foreach (IGrouping group in authored .GroupBy(static f => f.LayoutId) .OrderBy(static g => g.Key)) { Console.WriteLine( $"[INVISIBLE] layout=0x{group.Key:X8} count={group.Count()} ids=[" + string.Join(",", group.Select(static f => $"0x{f.ElementId:X8}")) + "]"); } Console.WriteLine( $"[INVISIBLE] authored={authored.Count} layouts=" + $"{authored.Select(static f => f.LayoutId).Distinct().Count()} " + $"built={built.Count} incorrectlyVisible={incorrectlyVisible.Count}"); // Keep the global threshold resilient to an installed DAT revision while // pinning landmarks from independent screens in both data and widgets. Assert.True(authored.Count >= 1_000, $"Expected the known client-wide 0x3B population, found {authored.Count}."); Assert.Contains(authored, static f => f.ElementId == 0x10000403u); // chargen GM label Assert.Contains(authored, static f => f.ElementId == 0x10000494u); // chargen envoy label Assert.Contains(authored, static f => f.ElementId == 0x100006A4u); // combat root Assert.Contains(authored, static f => f.ElementId == 0x1000048Cu); // chat new-text indicator Assert.Contains(built, static f => f.ElementId == 0x100006A4u); Assert.Contains(built, static f => f.ElementId == 0x1000048Cu); Assert.Empty(incorrectlyVisible); } private static void CollectAuthored(uint layoutId, ElementInfo node, List findings) { if (node.Invisible) findings.Add(new Finding(layoutId, node.Id)); foreach (ElementInfo child in node.Children) CollectAuthored(layoutId, child, findings); } private static void CollectBuilt( uint layoutId, UiElement node, List built, List incorrectlyVisible) { if (node.AuthoredInvisible) { var finding = new Finding(layoutId, node.DatElementId); built.Add(finding); if (node.Visible) incorrectlyVisible.Add(finding); } foreach (UiElement child in node.Children) CollectBuilt(layoutId, child, built, incorrectlyVisible); } }