From 9d8090fe0f47759e5d8f53e2b65ab7e5018a91ff Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 22 Jun 2026 14:48:38 +0100 Subject: [PATCH] Resolve Eve state refs through Verse client --- Aetheria.State.Verify/Program.cs | 23 ++++++-- .../Runtime/AetheriaEveSurfacePresenter.cs | 4 +- .../Runtime/AetheriaEveUnitySurfaceHost.cs | 4 +- .../Runtime/AetheriaRuntimeStateReader.cs | 2 +- .../Runtime/AetheriaRuntimeVerseClient.cs | 53 +++++++++++++++++++ 5 files changed, 78 insertions(+), 8 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 58c588052..2760b53f5 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -4611,7 +4611,8 @@ static void RequireInventoryCargoItemDetailsUseEveSurface(string root) !eveUnitySurfaceHost.Contains("ContainsStateRefs(surface)", StringComparison.Ordinal) || !eveUnitySurfaceHost.Contains("prop.Key.EndsWith(\"Ref\", StringComparison.Ordinal)", StringComparison.Ordinal) || !eveUnitySurfaceHost.Contains("CreateDefaultStateRefResolver()", StringComparison.Ordinal) || - !eveUnitySurfaceHost.Contains("AetheriaRuntimeStateReader.CreateEveSurfaceStateRefResolver(stateBoot.StateFilePath)", StringComparison.Ordinal) || + !eveUnitySurfaceHost.Contains("AetheriaRuntimeVerseClient.CreateEveSurfaceStateRefResolver(", StringComparison.Ordinal) || + !eveUnitySurfaceHost.Contains("\"unity-eve-surface-host\"", StringComparison.Ordinal) || !runtimeEveSurfaceAdapter.Contains("public static EveSurfaceDocument ResolveStateRefs(", StringComparison.Ordinal) || !runtimeEveSurfaceAdapter.Contains("ResolvePropRefs(props, stateRefResolver)", StringComparison.Ordinal) || !runtimeEveSurfaceAdapter.Contains("ResolvePropRef(props, AetheriaRuntimeSurfaceStateRefs.Source, \"value\", stateRefResolver)", StringComparison.Ordinal) || @@ -8130,6 +8131,9 @@ static void RequireAetheriaRuntimeVerseClientContract(string root) "GetPlayerSettingsAsync()", "GetVerseHostSettingsAsync()", "GetLoadoutTemplatesAsync()", + "CreateEveSurfaceStateRefResolver(", + "AetheriaRuntimeStateReader.TryResolveDaemonStateRef(", + "AetheriaRuntimeStateReader.TryResolveDaemonItemStatRef(", "SubmitDaemonCommandAsync(", "SubmitEveCommandAsync(", "AetheriaRuntimeVerseRecordKeys.DaemonCommand(command.CommandId)", @@ -10161,6 +10165,7 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) var actionGameManagerPath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs"); var mainMenuPath = Path.Combine(root, "Assets", "Scripts", "UI", "MainMenu.cs"); var eveSurfacePresenterPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.eve-runtime", "Runtime", "AetheriaEveSurfacePresenter.cs"); + var eveUnitySurfaceHostPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.eve-runtime", "Runtime", "AetheriaEveUnitySurfaceHost.cs"); var requiredPaths = new[] { @@ -10169,7 +10174,8 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) unityPackageProjectPath, actionGameManagerPath, mainMenuPath, - eveSurfacePresenterPath + eveSurfacePresenterPath, + eveUnitySurfaceHostPath }; var missingPaths = requiredPaths @@ -10190,6 +10196,7 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) var actionGameManager = File.ReadAllText(actionGameManagerPath); var mainMenu = File.ReadAllText(mainMenuPath); var eveSurfacePresenter = File.ReadAllText(eveSurfacePresenterPath); + var eveUnitySurfaceHost = File.ReadAllText(eveUnitySurfaceHostPath); var requiredReaderSymbols = new[] { @@ -10374,10 +10381,18 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) "Aetheria Eve surface presenter no longer routes daemon surface lookup through the shared runtime Verse client."); } - if (!eveSurfacePresenter.Contains("AetheriaRuntimeStateReader.CreateEveSurfaceStateRefResolver(statePath)", StringComparison.Ordinal)) + if (!eveSurfacePresenter.Contains("client.CreateEveSurfaceStateRefResolver()", StringComparison.Ordinal) || + !eveSurfacePresenter.Contains("ResolveVerseClient(statePath).CreateEveSurfaceStateRefResolver()", StringComparison.Ordinal)) { throw new InvalidOperationException( - "Aetheria Eve surface presenter no longer resolves provider state refs through the shared runtime state reader."); + "Aetheria Eve surface presenter no longer resolves provider state refs through the shared runtime Verse client."); + } + + if (eveSurfacePresenter.Contains("AetheriaRuntimeStateReader.CreateEveSurfaceStateRefResolver", StringComparison.Ordinal) || + eveUnitySurfaceHost.Contains("AetheriaRuntimeStateReader.CreateEveSurfaceStateRefResolver", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Unity Eve surface lowering still resolves state refs through the file reader instead of AetheriaRuntimeVerseClient."); } var forbiddenDirectStoreSymbols = new Dictionary diff --git a/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs b/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs index a9c888387..25466e9e1 100644 --- a/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs +++ b/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs @@ -129,7 +129,7 @@ namespace GameCult.Aetheria.EveRuntime ? null : AetheriaRuntimeEveSurfaceAdapter.ToEveSurfaceDocument( surface, - AetheriaRuntimeStateReader.CreateEveSurfaceStateRefResolver(statePath)); + client.CreateEveSurfaceStateRefResolver()); } private global::Aetheria.State.Documents.EveSurfaceState? ReadDaemonSurfaceState(AetheriaRuntimeVerseClient client) @@ -206,7 +206,7 @@ namespace GameCult.Aetheria.EveRuntime surface, request => EmitCommand(statePath, request), RootOnlyChrome, - AetheriaRuntimeStateReader.CreateEveSurfaceStateRefResolver(statePath)); + ResolveVerseClient(statePath).CreateEveSurfaceStateRefResolver()); _mountedStatePath = statePath; _mountedSurfaceId = surface.Surface.Id; _mountedSurfaceVersion = surface.Version; diff --git a/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveUnitySurfaceHost.cs b/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveUnitySurfaceHost.cs index 8587a3d9f..f6f320b0f 100644 --- a/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveUnitySurfaceHost.cs +++ b/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveUnitySurfaceHost.cs @@ -227,7 +227,9 @@ namespace GameCult.Aetheria.EveRuntime if (!stateBoot.SupportsLocalStateFileRead || !stateBoot.StateFileExists) return _ => ""; - return AetheriaRuntimeStateReader.CreateEveSurfaceStateRefResolver(stateBoot.StateFilePath); + return AetheriaRuntimeVerseClient.CreateEveSurfaceStateRefResolver( + stateBoot.StateFilePath, + "unity-eve-surface-host"); } } diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateReader.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateReader.cs index dd3b4af1a..12da87ea6 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateReader.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateReader.cs @@ -8,7 +8,7 @@ using GameCult.Eve.Surface; namespace GameCult.Aetheria.State.Verse { - // Runtime shells acquire typed state through this port so the transport can move to the daemon without spelunking every consumer. + // Compatibility reader for file-backed tools and pure state-ref helpers; Unity shells should prefer AetheriaRuntimeVerseClient. public static class AetheriaRuntimeStateReader { public static AetheriaRuntimeCatalogSnapshot OpenRuntimeCatalog(string stateFilePath) diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs index eb1f43d42..84d56e2d6 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs @@ -210,6 +210,23 @@ namespace GameCult.Aetheria.State.Verse return new AetheriaRuntimeVerseClient(fullPath, effectiveRuntimeId, node); } + public static Func CreateEveSurfaceStateRefResolver( + string statePath, + string runtimeId = DefaultRuntimeId) + { + if (string.IsNullOrWhiteSpace(statePath)) + return _ => ""; + + using var client = OpenAsync( + statePath, + string.IsNullOrWhiteSpace(runtimeId) ? DefaultRuntimeId : runtimeId, + startServer: false, + pullOnOpen: true) + .GetAwaiter() + .GetResult(); + return client.CreateEveSurfaceStateRefResolver(); + } + public Task GetProviderAdvertisementAsync() { ThrowIfDisposed(); @@ -291,6 +308,42 @@ namespace GameCult.Aetheria.State.Verse AetheriaRuntimeDaemonSoaViewStore.GetViewPath(StatePath)); } + public Func CreateEveSurfaceStateRefResolver() + { + ThrowIfDisposed(); + + var frame = GetLatestFrameAsync().GetAwaiter().GetResult(); + var health = GetHealthAsync().GetAwaiter().GetResult(); + var commandBoundary = GetCommandBoundaryAsync().GetAwaiter().GetResult(); + AetheriaRuntimeCatalogSnapshot? catalog = null; + + return stateRef => + { + if (string.IsNullOrWhiteSpace(stateRef)) + return ""; + + if (stateRef.StartsWith(AetheriaRuntimeDaemonStateRefs.Prefix + "/", StringComparison.Ordinal) && + AetheriaRuntimeStateReader.TryResolveDaemonStateRef( + frame, + health, + commandBoundary, + stateRef, + out var daemonValue)) + { + return daemonValue; + } + + if (stateRef.StartsWith(AetheriaRuntimeDaemonItemStatQueries.StateRefPrefix + "/", StringComparison.Ordinal)) + { + catalog ??= OpenRuntimeCatalog(); + if (AetheriaRuntimeStateReader.TryResolveDaemonItemStatRef(frame, catalog, stateRef, out var itemValue)) + return itemValue; + } + + return ""; + }; + } + public async Task GetLatestAuthoritativeRunFrameAsync() { ThrowIfDisposed();