From 6ca7fbc64b346c8a1ce9a1c020b61c81593f4f52 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 29 Jun 2026 08:10:36 +0100 Subject: [PATCH] Collapse runtime menu tab surface state --- Aetheria.State.Verify/Program.cs | 26 ++--- .../AetheriaRuntimeMenuTabsSurfaceBuilder.cs | 99 +++++-------------- 2 files changed, 36 insertions(+), 89 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index fede53731..42efec106 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -4867,7 +4867,6 @@ static void RequireRuntimeMenuTabsUseEveSurface(string root) "AetheriaRuntimeMenuTabsSurfaceBuilder.Compose(", "AetheriaRuntimeMenuTabsSurfaceBuilder.Project(", "new AetheriaRuntimeMenuTabProjectionOption(", - "new AetheriaRuntimeMenuTabSurfaceEntry(", "private static string TabKey(" }; @@ -4891,32 +4890,36 @@ static void RequireRuntimeMenuTabsUseEveSurface(string root) "MenuPanel tab visibility must read managed typed current-docking state instead of direct docking caches or ActionGameManager observed adapters."); } - var requiredProjectionBuilderSymbols = new[] + var requiredDocumentBuilderSymbols = new[] { "public sealed class AetheriaRuntimeMenuTabModelOption", "public static string NormalizeTabKey(string tabKey)", "public static AetheriaRuntimeSurfaceDocument Build(", - "private static AetheriaRuntimeMenuTabsSurfaceState ComposeState(", "public int Order { get; }", ".OrderBy(tab => tab.Order)", - "new AetheriaRuntimeMenuTabSurfaceEntry(", + "var normalizedCurrent = NormalizeTabKey(currentTabKey)", + "var tabs = (visibleTabs ?? Array.Empty())", + "var selected = string.Equals(key, normalizedCurrent, StringComparison.Ordinal)", "string.Equals(key, normalizedCurrent, StringComparison.Ordinal)" }; - var missingProjectionBuilderSymbols = requiredProjectionBuilderSymbols + var missingDocumentBuilderSymbols = requiredDocumentBuilderSymbols .Where(symbol => !menuTabsSurfaceBuilder.Contains(symbol, StringComparison.Ordinal)) .ToArray(); - if (missingProjectionBuilderSymbols.Length > 0) + if (missingDocumentBuilderSymbols.Length > 0) { throw new InvalidOperationException( - "Shared runtime menu tab surface builder no longer owns tab projection semantics: " + - string.Join(", ", missingProjectionBuilderSymbols)); + "Shared runtime menu tab surface builder no longer owns tab document composition semantics: " + + string.Join(", ", missingDocumentBuilderSymbols)); } if (menuTabsSurfaceBuilder.Contains("public static AetheriaRuntimeMenuTabsSurfaceState Compose(", StringComparison.Ordinal) || - menuTabsSurfaceBuilder.Contains("public static AetheriaRuntimeMenuTabsSurfaceState Project(", StringComparison.Ordinal)) + menuTabsSurfaceBuilder.Contains("public static AetheriaRuntimeMenuTabsSurfaceState Project(", StringComparison.Ordinal) || + menuTabsSurfaceBuilder.Contains("AetheriaRuntimeMenuTabsSurfaceState", StringComparison.Ordinal) || + menuTabsSurfaceBuilder.Contains("AetheriaRuntimeMenuTabSurfaceEntry", StringComparison.Ordinal) || + menuTabsSurfaceBuilder.Contains("ComposeState(", StringComparison.Ordinal)) { throw new InvalidOperationException( - "Runtime menu tab composition must stay behind Build(...); do not re-expose Compose/Project as the public tab surface path."); + "Runtime menu tab composition must emit the typed surface document directly; do not rebuild a shadow SurfaceState/Entry projection layer."); } var requiredDockedStoryObserverSymbols = new[] @@ -4996,8 +4999,7 @@ static void RequireRuntimeMenuTabsUseEveSurface(string root) "public static class AetheriaRuntimeMenuTabsSurfaceCommands", "public static bool TryRead(", "public static AetheriaRuntimeSurfaceDocument Build(", - "AetheriaRuntimeMenuTabsSurfaceState", - "AetheriaRuntimeMenuTabSurfaceEntry" + "var tabs = (visibleTabs ?? Array.Empty())" }; var missingBuilderSymbols = requiredBuilderSymbols .Where(symbol => !menuTabsSurfaceBuilder.Contains(symbol, StringComparison.Ordinal)) diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeMenuTabsSurfaceBuilder.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeMenuTabsSurfaceBuilder.cs index 735b6f904..ec49e97a5 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeMenuTabsSurfaceBuilder.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeMenuTabsSurfaceBuilder.cs @@ -5,37 +5,6 @@ using GameCult.Eve.Surface; namespace GameCult.Aetheria.State.Verse { - public sealed class AetheriaRuntimeMenuTabSurfaceEntry - { - public AetheriaRuntimeMenuTabSurfaceEntry(string key, string label, bool selected) - { - Key = key ?? ""; - Label = label ?? ""; - Selected = selected; - } - - public string Key { get; } - public string Label { get; } - public bool Selected { get; } - } - - public sealed class AetheriaRuntimeMenuTabsSurfaceState - { - public AetheriaRuntimeMenuTabsSurfaceState( - string currentTabKey, - IReadOnlyList visibleTabs, - string updatedAtUtc) - { - CurrentTabKey = currentTabKey ?? ""; - VisibleTabs = visibleTabs ?? Array.Empty(); - UpdatedAtUtc = updatedAtUtc ?? ""; - } - - public string CurrentTabKey { get; } - public IReadOnlyList VisibleTabs { get; } - public string UpdatedAtUtc { get; } - } - public sealed class AetheriaRuntimeMenuTabModelOption { public AetheriaRuntimeMenuTabModelOption(string key, string label, int order) @@ -71,55 +40,36 @@ namespace GameCult.Aetheria.State.Verse IEnumerable visibleTabs, string updatedAtUtc, long version = 1) - { - return Build( - ComposeState(currentTabKey, visibleTabs, updatedAtUtc), - version); - } - - private static AetheriaRuntimeMenuTabsSurfaceState ComposeState( - string currentTabKey, - IEnumerable visibleTabs, - string updatedAtUtc) { var normalizedCurrent = NormalizeTabKey(currentTabKey); - return new AetheriaRuntimeMenuTabsSurfaceState( - normalizedCurrent, - (visibleTabs ?? Array.Empty()) - .Where(tab => tab != null) - .OrderBy(tab => tab.Order) - .ThenBy(tab => NormalizeTabKey(tab.Key), StringComparer.Ordinal) - .Select(tab => + var tabs = (visibleTabs ?? Array.Empty()) + .Where(tab => tab != null) + .OrderBy(tab => tab.Order) + .ThenBy(tab => NormalizeTabKey(tab.Key), StringComparer.Ordinal) + .Select(tab => + { + var key = NormalizeTabKey(tab.Key); + var label = string.IsNullOrWhiteSpace(tab.Label) ? key : tab.Label; + var selected = string.Equals(key, normalizedCurrent, StringComparison.Ordinal); + return new { - var key = NormalizeTabKey(tab.Key); - return new AetheriaRuntimeMenuTabSurfaceEntry( - key, - string.IsNullOrWhiteSpace(tab.Label) ? key : tab.Label, - string.Equals(key, normalizedCurrent, StringComparison.Ordinal)); - }) - .ToArray(), - updatedAtUtc); - } + Key = key, + Label = label, + Selected = selected + }; + }) + .ToArray(); - public static AetheriaRuntimeSurfaceDocument Build( - AetheriaRuntimeMenuTabsSurfaceState state, - long version = 1) - { - state ??= new AetheriaRuntimeMenuTabsSurfaceState( - "", - Array.Empty(), - ""); - - var commands = state.VisibleTabs + var commands = tabs .Select(tab => new AetheriaRuntimeSurfaceCommandTemplate( CommandFor(tab.Key), - LabelFor(tab), + tab.Label, AetheriaRuntimeSurfaceCommandTemplate.CultMeshTransport)) .ToArray(); - var buttons = state.VisibleTabs + var buttons = tabs .Select(tab => Button( $"{SurfaceId}.{SafeId(tab.Key)}", - tab.Selected ? $"{LabelFor(tab)} *" : LabelFor(tab), + tab.Selected ? $"{tab.Label} *" : tab.Label, CommandFor(tab.Key))) .ToArray(); @@ -128,7 +78,7 @@ namespace GameCult.Aetheria.State.Verse providerKind: "runtime.menu", title: "Runtime Menu Tabs", version: version, - updatedAtUtc: state.UpdatedAtUtc, + updatedAtUtc: updatedAtUtc ?? "", surface: new AetheriaRuntimeSurfaceTree( SurfaceId, Node( @@ -137,17 +87,12 @@ namespace GameCult.Aetheria.State.Verse Array.Empty<(string Key, string Value)>(), Text( $"{SurfaceId}.current", - $"Current: {state.CurrentTabKey}"), + $"Current: {normalizedCurrent}"), ButtonRow($"{SurfaceId}.tabs", buttons)), Array.Empty()), commands: commands); } - private static string LabelFor(AetheriaRuntimeMenuTabSurfaceEntry tab) - { - return string.IsNullOrWhiteSpace(tab.Label) ? tab.Key : tab.Label; - } - private static string SafeId(string value) { if (string.IsNullOrWhiteSpace(value))