diff --git a/Aetheria.State/AetheriaEveSurfaceDocuments.cs b/Aetheria.State/AetheriaEveSurfaceDocuments.cs index 259bd2c84..7f2ee11f8 100644 --- a/Aetheria.State/AetheriaEveSurfaceDocuments.cs +++ b/Aetheria.State/AetheriaEveSurfaceDocuments.cs @@ -4,6 +4,10 @@ using System.Linq; using Aetheria.State.Documents; using GameCult.Aetheria.State.Verse; using GameCult.Mesh; +using EveDocumentCommandTemplate = Aetheria.State.Documents.EveCommandTemplate; +using EveDocumentStyleToken = Aetheria.State.Documents.EveStyleToken; +using EveDocumentSurface = Aetheria.State.Documents.EveSurface; +using EveDocumentSurfaceComponent = Aetheria.State.Documents.EveSurfaceComponent; namespace Aetheria.State; @@ -63,7 +67,7 @@ public static class AetheriaEveSurfaceDocuments Title = "Aetheria Catalog", Version = version, UpdatedAtUtc = updatedAtUtc, - Surface = new EveSurface + Surface = new EveDocumentSurface { Id = CatalogSurfaceId, Root = Node( @@ -93,7 +97,7 @@ public static class AetheriaEveSurfaceDocuments }, Commands = [ - new EveCommandTemplate + new EveDocumentCommandTemplate { Command = refreshCommand.OperationId, Label = refreshCommand.Label, @@ -131,7 +135,7 @@ public static class AetheriaEveSurfaceDocuments Title = "Aetheria Operations", Version = version, UpdatedAtUtc = updatedAtUtc, - Surface = new EveSurface + Surface = new EveDocumentSurface { Id = OperationsSurfaceId, Root = Node( @@ -188,7 +192,7 @@ public static class AetheriaEveSurfaceDocuments }, Commands = [ - new EveCommandTemplate + new EveDocumentCommandTemplate { Command = refreshCommand.OperationId, Label = refreshCommand.Label, @@ -231,12 +235,12 @@ public static class AetheriaEveSurfaceDocuments Title = surface.Title, Version = surface.Version, UpdatedAtUtc = surface.UpdatedAtUtc, - Surface = new EveSurface + Surface = new EveDocumentSurface { Id = surface.Surface.Id, Root = ConvertComponent(surface.Surface.Root), Styles = surface.Surface.Styles - .Select(style => new EveStyleToken + .Select(style => new EveDocumentStyleToken { Name = style.Name, Value = style.Value @@ -247,7 +251,7 @@ public static class AetheriaEveSurfaceDocuments .Select(command => { var record = CultMesh.OperationBindingRecord(command.Operation); - return new EveCommandTemplate + return new EveDocumentCommandTemplate { Command = record.OperationId, Label = record.Label, @@ -479,23 +483,23 @@ public static class AetheriaEveSurfaceDocuments return latest; } - private static EveSurfaceComponent Metric(string id, string label, string value) + private static EveDocumentSurfaceComponent Metric(string id, string label, string value) { return Node(id, "metric", [("label", label), ("value", value)]); } - private static EveSurfaceComponent Row(string id, params (string Key, string Value)[] props) + private static EveDocumentSurfaceComponent Row(string id, params (string Key, string Value)[] props) { return Node(id, "row", props); } - private static EveSurfaceComponent Node( + private static EveDocumentSurfaceComponent Node( string id, string kind, (string Key, string Value)[] props, - params EveSurfaceComponent[] children) + params EveDocumentSurfaceComponent[] children) { - return new EveSurfaceComponent + return new EveDocumentSurfaceComponent { Id = id, Kind = kind, @@ -504,9 +508,9 @@ public static class AetheriaEveSurfaceDocuments }; } - private static EveSurfaceComponent ConvertComponent(AetheriaRuntimeSurfaceComponent component) + private static EveDocumentSurfaceComponent ConvertComponent(AetheriaRuntimeSurfaceComponent component) { - return new EveSurfaceComponent + return new EveDocumentSurfaceComponent { Id = component.Id, Kind = component.Kind, diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeMainMenuSurfaceBuilder.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeMainMenuSurfaceBuilder.cs index 48f8dcf9d..c798f2c80 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeMainMenuSurfaceBuilder.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeMainMenuSurfaceBuilder.cs @@ -1,7 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using GameCult.Eve.Surface; +using GameCult.Mesh; +using EveUiCommandRequest = GameCult.Eve.Surface.EveSurfaceCommandRequest; namespace GameCult.Aetheria.State.Verse { @@ -150,60 +151,52 @@ namespace GameCult.Aetheria.State.Verse string updatedAtUtc, long version) { - var commands = new List(); - var actionButtons = new List(); + var builder = MainMenuSurface( + AetheriaRuntimeMainMenuCommands.RootSurfaceId, + "Aetheria Terminus", + updatedAtUtc, + version) + .TitleSubtitle("AETHERIA", "TERMINUS") + .ButtonColumn( + $"{AetheriaRuntimeMainMenuCommands.RootSurfaceId}.actions", + actions => + { + if (!inGame) + { + actions.Button( + "Continue", + Operation(AetheriaRuntimeMainMenuCommands.ContinueRun, "Continue")); + } - if (!inGame) - { - commands.Add(Command(AetheriaRuntimeMainMenuCommands.ContinueRun, "Continue")); - actionButtons.Add(Button( - $"{AetheriaRuntimeMainMenuCommands.RootSurfaceId}.continue", - "Continue", - AetheriaRuntimeMainMenuCommands.ContinueRun)); - } + actions.Button("New Game", Operation(AetheriaRuntimeMainMenuCommands.NewGame, "New Game")); + actions.Button("Settings", Operation(AetheriaRuntimeMainMenuCommands.ShowSettings, "Settings")); + actions.Button("Quit", Operation(AetheriaRuntimeMainMenuCommands.Quit, "Quit")); + }); - commands.Add(Command(AetheriaRuntimeMainMenuCommands.NewGame, "New Game")); - commands.Add(Command(AetheriaRuntimeMainMenuCommands.ShowSettings, "Settings")); - commands.Add(Command(AetheriaRuntimeMainMenuCommands.Quit, "Quit")); - - actionButtons.Add(Button($"{AetheriaRuntimeMainMenuCommands.RootSurfaceId}.newGame", "New Game", AetheriaRuntimeMainMenuCommands.NewGame)); - actionButtons.Add(Button($"{AetheriaRuntimeMainMenuCommands.RootSurfaceId}.settings", "Settings", AetheriaRuntimeMainMenuCommands.ShowSettings)); - actionButtons.Add(Button($"{AetheriaRuntimeMainMenuCommands.RootSurfaceId}.quit", "Quit", AetheriaRuntimeMainMenuCommands.Quit)); - - return BuildSurfaceDocument( - AetheriaRuntimeMainMenuCommands.RootSurfaceId, - "Aetheria Terminus", - updatedAtUtc, - version, - commands, - Text($"{AetheriaRuntimeMainMenuCommands.RootSurfaceId}.title", "AETHERIA", "text.title"), - Text($"{AetheriaRuntimeMainMenuCommands.RootSurfaceId}.subtitle", "TERMINUS", "text.subtitle"), - ButtonColumn($"{AetheriaRuntimeMainMenuCommands.RootSurfaceId}.actions", actionButtons.ToArray())); + return AetheriaRuntimeSurfaceDocuments.FromPortableSurface(builder.Build()); } public static AetheriaRuntimeSurfaceDocument BuildSettings( string updatedAtUtc, long version = 1) { - return BuildSurfaceDocument( - AetheriaRuntimeMainMenuCommands.SettingsSurfaceId, - "Aetheria Settings", - updatedAtUtc, - version, - new[] - { - Command(AetheriaRuntimeMainMenuCommands.ShowPlayerSettings, "Player Settings"), - Command(AetheriaRuntimeMainMenuCommands.ShowVerseSettings, "Verse"), - Command(AetheriaRuntimeMainMenuCommands.ShowInputSettings, "Input"), - Command(AetheriaRuntimeMainMenuCommands.BackToMain, "Back") - }, - Text("aetheria.mainMenu.settings.title", "SETTINGS", "text.title"), - ButtonColumn( + var builder = MainMenuSurface( + AetheriaRuntimeMainMenuCommands.SettingsSurfaceId, + "Aetheria Settings", + updatedAtUtc, + version) + .Title("SETTINGS") + .ButtonColumn( "aetheria.mainMenu.settings.actions", - Button("aetheria.mainMenu.settings.playerSettings", "Player Settings", AetheriaRuntimeMainMenuCommands.ShowPlayerSettings), - Button("aetheria.mainMenu.settings.verse", "Verse", AetheriaRuntimeMainMenuCommands.ShowVerseSettings), - Button("aetheria.mainMenu.settings.input", "Input", AetheriaRuntimeMainMenuCommands.ShowInputSettings), - Button("aetheria.mainMenu.settings.back", "Back", AetheriaRuntimeMainMenuCommands.BackToMain))); + actions => + { + actions.Button("Player Settings", Operation(AetheriaRuntimeMainMenuCommands.ShowPlayerSettings, "Player Settings")); + actions.Button("Verse", Operation(AetheriaRuntimeMainMenuCommands.ShowVerseSettings, "Verse")); + actions.Button("Input", Operation(AetheriaRuntimeMainMenuCommands.ShowInputSettings, "Input")); + actions.Button("Back", Operation(AetheriaRuntimeMainMenuCommands.BackToMain, "Back")); + }); + + return AetheriaRuntimeSurfaceDocuments.FromPortableSurface(builder.Build()); } private static AetheriaRuntimeSurfaceDocument BuildInputSettings( @@ -214,63 +207,52 @@ namespace GameCult.Aetheria.State.Verse string updatedAtUtc, long version) { - var commands = new List - { - Command(AetheriaRuntimeMainMenuCommands.BackToSettings, "Back") - }; - - var children = new List - { - Text("aetheria.mainMenu.input.title", "INPUT", "text.title"), - Metric( - "aetheria.mainMenu.input.bindingOverrides", - "Binding Overrides", - bindingOverrideCount.ToString()), - Metric( - "aetheria.mainMenu.input.actionBarInputs", - "Action-Bar Inputs", - actionBarInputCount.ToString()) - }; + var builder = MainMenuSurface( + AetheriaRuntimeMainMenuCommands.InputSettingsSurfaceId, + "Aetheria Input Settings", + updatedAtUtc, + version) + .Title("INPUT") + .Form( + "aetheria.mainMenu.input.metrics", + form => form + .Metric("Binding Overrides", bindingOverrideCount.ToString()) + .Metric("Action-Bar Inputs", actionBarInputCount.ToString())); if (canOpenRuntimeInputScreen) { - commands.Insert(0, Command(AetheriaRuntimeMainMenuCommands.OpenRuntimeInputScreen, "Open Remap Screen")); - children.Add(Text( - "aetheria.mainMenu.input.note", - "The runtime Eve input screen owns low-level InputSystem rebinding and action-bar input edits. This title shell reports typed player-settings state and hands off to that owner.")); + builder.Text( + "The runtime Eve input screen owns low-level InputSystem rebinding and action-bar input edits. This title shell reports typed player-settings state and hands off to that owner.", + "aetheria.mainMenu.input.note"); } else if (inGame) { - children.Add(Text( - "aetheria.mainMenu.input.note", - "The runtime Eve input screen should own rebinding here, but this scene has no active input surface to hand off to.")); + builder.Text( + "The runtime Eve input screen should own rebinding here, but this scene has no active input surface to hand off to.", + "aetheria.mainMenu.input.note"); } else { - children.Add(Text( - "aetheria.mainMenu.input.note", - "This title shell reports the typed player-settings state. Launch a run to open the runtime Eve input screen that owns low-level InputSystem rebinding.")); + builder.Text( + "This title shell reports the typed player-settings state. Launch a run to open the runtime Eve input screen that owns low-level InputSystem rebinding.", + "aetheria.mainMenu.input.note"); } - var buttons = new List(); - if (canOpenRuntimeInputScreen) - { - buttons.Add(Button( - "aetheria.mainMenu.input.openRuntimeScreen", - "Open Remap Screen", - AetheriaRuntimeMainMenuCommands.OpenRuntimeInputScreen)); - } + builder.ButtonColumn( + "aetheria.mainMenu.input.actions", + actions => + { + if (canOpenRuntimeInputScreen) + { + actions.Button( + "Open Remap Screen", + Operation(AetheriaRuntimeMainMenuCommands.OpenRuntimeInputScreen, "Open Remap Screen")); + } - buttons.Add(Button("aetheria.mainMenu.input.back", "Back", AetheriaRuntimeMainMenuCommands.BackToSettings)); - children.Add(ButtonColumn("aetheria.mainMenu.input.actions", buttons.ToArray())); + actions.Button("Back", Operation(AetheriaRuntimeMainMenuCommands.BackToSettings, "Back")); + }); - return BuildSurfaceDocument( - AetheriaRuntimeMainMenuCommands.InputSettingsSurfaceId, - "Aetheria Input Settings", - updatedAtUtc, - version, - commands, - children.ToArray()); + return AetheriaRuntimeSurfaceDocuments.FromPortableSurface(builder.Build()); } public static AetheriaRuntimeSurfaceDocument BuildVerseSettingsShell( @@ -314,32 +296,21 @@ namespace GameCult.Aetheria.State.Verse .ToArray()); } - private static string VerseLabel(string verseTitle, string verseId) - { - var title = string.IsNullOrWhiteSpace(verseTitle) ? "Unknown Verse" : verseTitle; - var id = string.IsNullOrWhiteSpace(verseId) ? "unknown" : verseId; - return string.Equals(title, id, StringComparison.Ordinal) ? title : $"{title} ({id})"; - } - - private static AetheriaRuntimeSurfaceDocument BuildSurfaceDocument( + private static GameCult.Mesh.EveSurfaceBuilder MainMenuSurface( string surfaceId, string title, string updatedAtUtc, - long version, - IReadOnlyList commands, - params AetheriaRuntimeSurfaceComponent[] children) + long version) { - return new AetheriaRuntimeSurfaceDocument( - providerId: ProviderId, - providerKind: ProviderKind, - title: title, - version: version, - updatedAtUtc: updatedAtUtc, - surface: new AetheriaRuntimeSurfaceTree( - surfaceId, - Node($"{surfaceId}.root", "surface", Array.Empty<(string Key, string Value)>(), children), - MainMenuStyleTokens()), - commands: commands); + var builder = GameCult.Mesh.EveSurface.Create(surfaceId) + .Provider(ProviderId, ProviderKind) + .Version(version) + .UpdatedAtUtc(updatedAtUtc); + + foreach (var token in MainMenuStyleTokens()) + builder.Style(token.Name, token.Value); + + return builder; } private static IReadOnlyList MainMenuStyleTokens() @@ -363,17 +334,14 @@ namespace GameCult.Aetheria.State.Verse return new AetheriaRuntimeSurfaceCommandTemplate(command, label, AetheriaRuntimeSurfaceCommandTemplate.CultMeshTransport); } - private static AetheriaRuntimeSurfaceComponent Card( - string id, - string title, - params AetheriaRuntimeSurfaceComponent[] children) + private static CultMeshOperationBindingDescriptor Operation(string command, string label) { - return Node(id, "card", new[] { ("title", title) }, children); - } - - private static AetheriaRuntimeSurfaceComponent Metric(string id, string label, string value) - { - return Node(id, "metric", new[] { ("label", label), ("value", value ?? "") }); + return CultMesh.OperationBindingRecord( + command, + label, + "", + nameof(CultMeshLocalityKind.Automatic), + AetheriaRuntimeSurfaceCommandTemplate.CultMeshTransport).ToBinding(); } private static AetheriaRuntimeSurfaceComponent Text(string id, string value) @@ -454,7 +422,7 @@ namespace GameCult.Aetheria.State.Verse public static class AetheriaRuntimeMainMenuSurfaceCommands { public static bool TryRead( - EveSurfaceCommandRequest request, + EveUiCommandRequest request, out AetheriaRuntimeMainMenuCommand command) { command = default; diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeSurfaceDocuments.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeSurfaceDocuments.cs index a4f498763..c2ddb501d 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeSurfaceDocuments.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeSurfaceDocuments.cs @@ -2,10 +2,15 @@ using System; using System.Collections.Generic; using System.Linq; using GameCult.Caching; -using GameCult.Eve.Surface; using GameCult.Mesh; using MessagePack; using EveSurfaceState = global::Aetheria.State.Documents.EveSurfaceState; +using EveUiCommandTemplate = GameCult.Eve.Surface.EveCommandTemplate; +using EveUiEmbeddedDocumentSlot = GameCult.Eve.Surface.EveEmbeddedDocumentSlot; +using EveUiStyleToken = GameCult.Eve.Surface.EveStyleToken; +using EveUiSurfaceComponent = GameCult.Eve.Surface.EveSurfaceComponent; +using EveUiSurfaceDocument = GameCult.Eve.Surface.EveSurfaceDocument; +using EveUiSurfaceTree = GameCult.Eve.Surface.EveSurfaceTree; #nullable enable @@ -264,23 +269,45 @@ namespace GameCult.Aetheria.State.Verse }; } - public static EveSurfaceDocument ToEveSurfaceDocument(AetheriaRuntimeSurfaceDocument document) + public static AetheriaRuntimeSurfaceDocument FromPortableSurface(GameCult.Mesh.EveSurfaceDocument document) + { + if (document == null) throw new ArgumentNullException(nameof(document)); + + return new AetheriaRuntimeSurfaceDocument( + document.ProviderId, + document.ProviderKind, + document.Title, + document.Version, + document.UpdatedAtUtc, + new AetheriaRuntimeSurfaceTree( + document.Surface.Id, + FromPortableComponent(document.Surface.Root), + document.Surface.Styles + .Select(style => new AetheriaRuntimeSurfaceStyleToken(style.Name, style.Value)) + .ToArray()), + document.Commands + .Select(command => new AetheriaRuntimeSurfaceCommandTemplate( + FromPortableOperation(command.Operation))) + .ToArray()); + } + + public static EveUiSurfaceDocument ToEveSurfaceDocument(AetheriaRuntimeSurfaceDocument document) { return ToEveSurfaceDocument(document, null); } - public static EveSurfaceDocument ToEveSurfaceDocument(EveSurfaceState state) + public static EveUiSurfaceDocument ToEveSurfaceDocument(EveSurfaceState state) { return ToEveSurfaceDocument(state, null); } - public static EveSurfaceDocument ToEveSurfaceDocument( + public static EveUiSurfaceDocument ToEveSurfaceDocument( EveSurfaceState state, CultMeshStateRefResolver? stateRefResolver) { if (state == null) throw new ArgumentNullException(nameof(state)); - var surface = new EveSurfaceDocument( + var surface = new EveUiSurfaceDocument( state.Type, state.Schema, state.ProviderId, @@ -288,27 +315,27 @@ namespace GameCult.Aetheria.State.Verse state.Title, state.Version, state.UpdatedAtUtc, - new EveSurfaceTree( + new EveUiSurfaceTree( state.Surface.Id, ToEveSurfaceComponent(state.Surface.Root), state.Surface.Styles - .Select(style => new EveStyleToken(style.Name, style.Value)) + .Select(style => new EveUiStyleToken(style.Name, style.Value)) .ToArray()), state.Commands - .Select(command => new EveCommandTemplate( + .Select(command => new EveUiCommandTemplate( ToCultMeshOperationBinding(command))) .ToArray()); return ResolveStateRefs(surface, stateRefResolver); } - public static EveSurfaceDocument ToEveSurfaceDocument( + public static EveUiSurfaceDocument ToEveSurfaceDocument( AetheriaRuntimeSurfaceDocument document, CultMeshStateRefResolver? stateRefResolver) { if (document == null) throw new ArgumentNullException(nameof(document)); - var surface = new EveSurfaceDocument( + var surface = new EveUiSurfaceDocument( "surface-state", "gamecult.eve.surface.v1", document.ProviderId, @@ -316,21 +343,21 @@ namespace GameCult.Aetheria.State.Verse document.Title, document.Version, document.UpdatedAtUtc, - new EveSurfaceTree( + new EveUiSurfaceTree( document.Surface.Id, ToEveSurfaceComponent(document.Surface.Root), document.Surface.Styles - .Select(style => new EveStyleToken(style.Name, style.Value)) + .Select(style => new EveUiStyleToken(style.Name, style.Value)) .ToArray()), document.Commands - .Select(command => new EveCommandTemplate(command.Operation)) + .Select(command => new EveUiCommandTemplate(command.Operation)) .ToArray()); return ResolveStateRefs(surface, stateRefResolver); } - public static EveSurfaceDocument ResolveStateRefs( - EveSurfaceDocument surface, + public static EveUiSurfaceDocument ResolveStateRefs( + EveUiSurfaceDocument surface, CultMeshStateRefResolver? stateRefResolver) { if (surface == null) throw new ArgumentNullException(nameof(surface)); @@ -338,7 +365,7 @@ namespace GameCult.Aetheria.State.Verse return surface; var resolveStateRef = stateRefResolver.AsFunc(); - return new EveSurfaceDocument( + return new EveUiSurfaceDocument( surface.Type, surface.Schema, surface.ProviderId, @@ -346,17 +373,17 @@ namespace GameCult.Aetheria.State.Verse surface.Title, surface.Version, surface.UpdatedAtUtc, - new EveSurfaceTree( + new EveUiSurfaceTree( surface.Surface.Id, ResolveStateRefs(surface.Surface.Root, resolveStateRef), surface.Surface.Styles), surface.Commands); } - public static EveSurfaceDocument EmptySurface(string surfaceId) + public static EveUiSurfaceDocument EmptySurface(string surfaceId) { var id = string.IsNullOrWhiteSpace(surfaceId) ? "aetheria.surface.missing" : surfaceId; - return new EveSurfaceDocument( + return new EveUiSurfaceDocument( "surface-state", "gamecult.eve.surface.v1", "aetheria.daemon", @@ -364,22 +391,22 @@ namespace GameCult.Aetheria.State.Verse "", 0, "", - new EveSurfaceTree( + new EveUiSurfaceTree( id, - new EveSurfaceComponent( + new EveUiSurfaceComponent( id + ".missing", "surface", new Dictionary(StringComparer.Ordinal), - Array.Empty()), - Array.Empty()), - Array.Empty()); + Array.Empty()), + Array.Empty()), + Array.Empty()); } - private static EveSurfaceComponent ToEveSurfaceComponent(AetheriaRuntimeSurfaceComponent component) + private static EveUiSurfaceComponent ToEveSurfaceComponent(AetheriaRuntimeSurfaceComponent component) { var props = new Dictionary(component.Props, StringComparer.Ordinal); AetheriaRuntimeSurfaceStateBindings.AddPointerProps(props, component.StateBindings); - return new EveSurfaceComponent( + return new EveUiSurfaceComponent( component.Id, component.Kind, props, @@ -435,7 +462,7 @@ namespace GameCult.Aetheria.State.Verse }; } - private static EveSurfaceComponent ToEveSurfaceComponent(global::Aetheria.State.Documents.EveSurfaceComponent component) + private static EveUiSurfaceComponent ToEveSurfaceComponent(global::Aetheria.State.Documents.EveSurfaceComponent component) { var props = new Dictionary(component.Props, StringComparer.Ordinal); var stateBindings = (component.StateBindings ?? Array.Empty()) @@ -444,7 +471,7 @@ namespace GameCult.Aetheria.State.Verse AetheriaRuntimeSurfaceStateBindings.AddPointerProps( props, stateBindings); - return new EveSurfaceComponent( + return new EveUiSurfaceComponent( component.Id, component.Kind, props, @@ -452,9 +479,9 @@ namespace GameCult.Aetheria.State.Verse stateBindings.Select(ToCultMeshStateBinding).ToArray()); } - private static EveEmbeddedDocumentSlot ToEveEmbeddedDocumentSlot(AetheriaRuntimeEmbeddedDocumentSlot slot) + private static EveUiEmbeddedDocumentSlot ToEveEmbeddedDocumentSlot(AetheriaRuntimeEmbeddedDocumentSlot slot) { - return new EveEmbeddedDocumentSlot( + return new EveUiEmbeddedDocumentSlot( slot.SlotId, slot.DocumentId, slot.SchemaId, @@ -497,14 +524,14 @@ namespace GameCult.Aetheria.State.Verse routeDescription).ToBinding(); } - private static EveSurfaceComponent ResolveStateRefs( - EveSurfaceComponent component, + private static EveUiSurfaceComponent ResolveStateRefs( + EveUiSurfaceComponent component, Func resolveStateRef) { var props = new Dictionary(component.Props, StringComparer.Ordinal); ResolvePropRefs(props, resolveStateRef); - return new EveSurfaceComponent( + return new EveUiSurfaceComponent( component.Id, component.Kind, props, @@ -513,19 +540,69 @@ namespace GameCult.Aetheria.State.Verse component.EmbeddedDocuments); } - private static IReadOnlyList ResolveStateRefs( - IReadOnlyList children, + private static IReadOnlyList ResolveStateRefs( + IReadOnlyList children, Func resolveStateRef) { if (children == null || children.Count == 0) - return Array.Empty(); + return Array.Empty(); - var resolved = new EveSurfaceComponent[children.Count]; + var resolved = new EveUiSurfaceComponent[children.Count]; for (var index = 0; index < children.Count; index++) resolved[index] = ResolveStateRefs(children[index], resolveStateRef); return resolved; } + private static AetheriaRuntimeSurfaceComponent FromPortableComponent(GameCult.Mesh.EveSurfaceComponent component) + { + return new AetheriaRuntimeSurfaceComponent( + component.Id, + component.Kind, + new Dictionary(component.Props, StringComparer.Ordinal), + component.Children.Select(FromPortableComponent).ToArray(), + component.StateBindings.Select(FromPortableStateBinding).ToArray(), + component.EmbeddedDocuments.Select(FromPortableEmbeddedDocumentSlot).ToArray()); + } + + private static AetheriaRuntimeEmbeddedDocumentSlot FromPortableEmbeddedDocumentSlot( + GameCult.Mesh.EveEmbeddedDocumentSlot slot) + { + return new AetheriaRuntimeEmbeddedDocumentSlot( + slot.SlotId, + slot.DocumentId, + slot.SchemaId, + slot.PresentationKind, + FromPortableRoute(slot.RouteHint)); + } + + private static CultMeshStateBindingDescriptor FromPortableStateBinding( + GameCult.Mesh.EveSurfaceStateBinding binding) + { + return CultMesh.StateBindingRecord( + binding.TargetProp, + binding.PointerId, + binding.SourceId, + binding.SchemaId, + binding.RouteHint.Kind, + binding.RouteHint.Description).ToBinding(); + } + + private static CultMeshOperationBindingDescriptor FromPortableOperation( + GameCult.Mesh.EveSurfaceOperationBinding operation) + { + return CultMesh.OperationBindingRecord( + operation.OperationId, + operation.Label, + operation.SchemaId, + operation.RouteHint.Kind, + operation.RouteHint.Description).ToBinding(); + } + + private static CultMeshRouteHint FromPortableRoute(GameCult.Mesh.EveSurfaceRouteHint route) + { + return new CultMeshRouteRecord(route.Kind, route.Description).ToRoute(CultMeshRouteHint.Automatic); + } + private static void ResolvePropRefs( Dictionary props, Func resolveStateRef)