using System; using System.Collections.Generic; using System.IO; using System.Text; namespace IdleSpectator; public sealed class CameraAInventoryResult { public bool Passed; public string Detail = ""; public int Total; public int CameraA; public int CameraB; } /// /// Live dump of Layer A vs B fate for decisions + library dial domains. /// Source of truth for Signal / decision promote work (never promote from memory). /// public static class CameraAInventoryHarness { public static CameraAInventoryResult RunAudit(string outputDirectory) { var lines = new List { "domain\tid\tdisplay\tlayer\tstrength\treason" }; int total = 0; int cameraA = 0; int cameraB = 0; var summary = new StringBuilder(); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "decisions", "decision", ActivityAssetCatalog.EnumerateLiveDecisionIds(), id => EventCatalog.Decision.GetOrFallback(id), id => EventCatalog.Decision.IsCameraWorthy(id) ? (EventCatalog.Decision.TryGetAuthoredActionPhrase(id, out _) ? "signal_predicate+phrase" : "signal_predicate") : ReasonDecisionB(id)); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "spells", "spell", ActivityAssetCatalog.EnumerateLiveSpellIds(), EventCatalog.Spell.GetOrFallback, id => ReasonLibrary(EventCatalog.Spell.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "powers", "power", ActivityAssetCatalog.EnumerateLivePowerIds(), EventCatalog.Power.GetOrFallback, id => ReasonLibrary(EventCatalog.Power.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "items", "item", ActivityAssetCatalog.EnumerateLiveItemIds(), EventCatalog.Item.GetOrFallback, id => ReasonLibrary(EventCatalog.Item.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "genes", "gene", ActivityAssetCatalog.EnumerateLiveGeneIds(), EventCatalog.Gene.GetOrFallback, id => ReasonLibrary(EventCatalog.Gene.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "phenotypes", "phenotype", ActivityAssetCatalog.EnumerateLivePhenotypeIds(), EventCatalog.Phenotype.GetOrFallback, id => ReasonLibrary(EventCatalog.Phenotype.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "world_laws", "worldlaw", ActivityAssetCatalog.EnumerateLiveWorldLawIds(), EventCatalog.WorldLaw.GetOrFallback, id => ReasonLibrary(EventCatalog.WorldLaw.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "subspecies_traits", "subspecies_trait", ActivityAssetCatalog.EnumerateLiveSubspeciesTraitIds(), EventCatalog.SubspeciesTrait.GetOrFallback, id => ReasonLibrary(EventCatalog.SubspeciesTrait.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "biomes", "biome", ActivityAssetCatalog.EnumerateLiveBiomeIds(), EventCatalog.Biome.GetOrFallback, id => ReasonLibrary(EventCatalog.Biome.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "culture_traits", "culture_trait", ActivityAssetCatalog.EnumerateLiveCultureTraitIds(), EventCatalog.CultureTrait.GetOrFallback, id => ReasonLibrary(EventCatalog.CultureTrait.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "religion_traits", "religion_trait", ActivityAssetCatalog.EnumerateLiveReligionTraitIds(), EventCatalog.ReligionTrait.GetOrFallback, id => ReasonLibrary(EventCatalog.ReligionTrait.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "clan_traits", "clan_trait", ActivityAssetCatalog.EnumerateLiveClanTraitIds(), EventCatalog.ClanTrait.GetOrFallback, id => ReasonLibrary(EventCatalog.ClanTrait.GetOrFallback(id))); AppendDomain( lines, ref total, ref cameraA, ref cameraB, summary, "language_traits", "language_trait", ActivityAssetCatalog.EnumerateLiveLanguageTraitIds(), EventCatalog.LanguageTrait.GetOrFallback, id => ReasonLibrary(EventCatalog.LanguageTrait.GetOrFallback(id))); try { if (!string.IsNullOrEmpty(outputDirectory)) { Directory.CreateDirectory(outputDirectory); File.WriteAllLines(Path.Combine(outputDirectory, "camera-a-inventory.tsv"), lines); File.WriteAllText( Path.Combine(outputDirectory, "camera-a-inventory-summary.txt"), summary.ToString()); } } catch { // diagnostic dump only } bool passed = total > 0 && cameraA > 0; return new CameraAInventoryResult { Passed = passed, Total = total, CameraA = cameraA, CameraB = cameraB, Detail = $"total={total} A={cameraA} B={cameraB} domains=13" }; } private static void AppendDomain( List lines, ref int total, ref int cameraA, ref int cameraB, StringBuilder summary, string domain, string displayKind, List ids, Func getEntry, Func reasonFor) { if (ids == null) { ids = new List(); } int a = 0; int b = 0; for (int i = 0; i < ids.Count; i++) { string id = ids[i]; if (string.IsNullOrEmpty(id)) { continue; } DiscreteEventEntry entry = getEntry(id); bool isA = entry != null && EventCatalog.IsCameraWorthy(entry); string layer = isA ? "A" : "B"; if (isA) { a++; cameraA++; } else { b++; cameraB++; } total++; string display = domain == "decisions" ? EventReason.HumanizeId(id) : LibraryAssetNames.DisplayName(displayKind, id); display = SanitizeTsv(display); float strength = entry != null ? entry.EventStrength : 0f; string reason = SanitizeTsv(reasonFor(id) ?? ""); lines.Add( domain + "\t" + id + "\t" + display + "\t" + layer + "\t" + strength.ToString("0.#") + "\t" + reason); } summary.AppendLine(domain + "\tlive=" + ids.Count + "\tA=" + a + "\tB=" + b); } private static string ReasonLibrary(DiscreteEventEntry entry) { if (entry == null) { return "missing"; } if (entry.IsFallback) { return "fallback"; } return entry.CreatesInterest ? "signal" : "ambient"; } private static string ReasonDecisionB(string id) { if (string.IsNullOrEmpty(id)) { return "empty"; } string s = id.ToLowerInvariant(); if (s == "try_new_plot" || s.StartsWith("try_new_plot_", StringComparison.Ordinal)) { return "deny_plot_intent"; } if (s.Contains("start_new_civilization") || s.Contains("start_new_civ") || s.Contains("build_civ_city") || s.Contains("city_foundation") || s == "claim_land" || s.StartsWith("claim_land_", StringComparison.Ordinal)) { return "deny_genesis_intent"; } if (s.Contains("idle") || s.Contains("walking") || s.Contains("check") || s.Contains("wait") || s.Contains("sleep") || s.Contains("random") || s.Contains("play") || s.Contains("jump") || s.Contains("flip") || s.Contains("diet_") || s.Contains("move") || s.Contains("swim") || s.Contains("follow_parent") || s.Contains("follow_desire") || s.Contains("reflection") || s.Contains("poop")) { return "deny_fluff"; } return "no_signal_token"; } private static string SanitizeTsv(string value) { if (string.IsNullOrEmpty(value)) { return ""; } return value.Replace('\t', ' ').Replace('\n', ' ').Replace('\r', ' '); } }