Read main menu daemon frame through Verse client

This commit is contained in:
Meta Vens 2026-06-22 14:17:23 +01:00
commit c079a554f7
3 changed files with 78 additions and 23 deletions

View file

@ -6347,6 +6347,8 @@ static void RequireClientTargetBootAuthority(string root)
{
"CurrentStateBoot()",
"LatestDaemonFrame(AetheriaRuntimeStateBootReport stateBoot)",
"AetheriaRuntimeVerseClient",
"GetLatestAuthoritativeRunFrameAsync()",
"LatestVerseHostSettings(AetheriaRuntimeStateBootReport stateBoot)",
"AetheriaState.At(ActionGameManager.GameDataDirectory)",
".ClientTarget",
@ -8117,6 +8119,8 @@ static void RequireAetheriaRuntimeVerseClientContract(string root)
"WatchDaemonGameTuiSurfaces()",
"WatchDaemonEditorTuiSurfaces()",
"AetheriaRuntimeVerseDocument<EveSurfaceState>",
"GetLatestAuthoritativeRunFrameAsync()",
"GetObservedDaemonStateAsync()",
"SubmitDaemonCommandAsync(",
"AetheriaRuntimeVerseRecordKeys.DaemonCommand(command.CommandId)",
"DaemonGameTuiSurface { get; }",
@ -8708,9 +8712,8 @@ static void RequireMainMenuContinueRunState(string root)
var requiredMenuSymbols = new[]
{
"LatestDaemonFrame",
"AetheriaRuntimeStateReader",
"TryReadDaemonFrame(stateBoot.StateFilePath, out var frame)",
"frame.IsAuthoritative",
"AetheriaRuntimeVerseClient",
"GetLatestAuthoritativeRunFrameAsync()",
"ContinueGame()",
"ActionGameManager.ObservedGalaxy = Galaxy.ProjectObservedDaemonRun(",
"SceneManager.LoadScene(\"ARPG\")"
@ -9691,8 +9694,8 @@ static void RequireUnityObserverDoesNotTickLocalSimulation(string root)
var requiredMenuSymbols = new[]
{
"TryStartDaemonObservedGame",
"TryReadDaemonFrame(stateBoot.StateFilePath, out var frame)",
"frame.IsAuthoritative",
"LatestDaemonFrame(stateBoot)",
"GetLatestAuthoritativeRunFrameAsync()",
"ActionGameManager.ObservedGalaxy = Galaxy.ProjectObservedDaemonRun(",
"frame.Run",
"SceneManager.LoadScene(\"ARPG\")"
@ -10335,11 +10338,17 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root)
"AetheriaDaemonObserver still spelunks observed daemon state through the runtime file reader instead of the Verse client.");
}
if (!mainMenu.Contains("AetheriaRuntimeStateReader", StringComparison.Ordinal) ||
!mainMenu.Contains("TryReadDaemonFrame(stateBoot.StateFilePath, out var frame)", StringComparison.Ordinal))
if (!mainMenu.Contains("AetheriaRuntimeVerseClient", StringComparison.Ordinal) ||
!mainMenu.Contains("GetLatestAuthoritativeRunFrameAsync()", StringComparison.Ordinal))
{
throw new InvalidOperationException(
"MainMenu no longer routes daemon-frame lookup through the shared runtime state reader.");
"MainMenu no longer routes daemon-frame lookup through the shared runtime Verse client.");
}
if (mainMenu.Contains("AetheriaRuntimeStateReader.TryReadDaemonFrame", StringComparison.Ordinal))
{
throw new InvalidOperationException(
"MainMenu still reads daemon frames through the runtime file reader instead of the Verse client.");
}
if (!eveSurfacePresenter.Contains("AetheriaRuntimeVerseClient.OpenAsync(", StringComparison.Ordinal) ||

View file

@ -17,6 +17,8 @@ public class MainMenu : MonoBehaviour
public bool InGame;
private UIDocument _menuSurfaceDocument;
private AetheriaRuntimeVerseClient _verseClient;
private string _verseClientStatePath;
private readonly AetheriaEveUnitySurfaceChrome _menuSurfaceChrome = new AetheriaEveUnitySurfaceChrome
{
RootAlignItems = Align.Center,
@ -108,14 +110,10 @@ public class MainMenu : MonoBehaviour
private bool TryStartDaemonObservedGame(string title)
{
var stateBoot = CurrentStateBoot();
if (!AetheriaRuntimeStateReader.TryReadDaemonFrame(stateBoot.StateFilePath, out var frame) ||
frame == null ||
!frame.IsAuthoritative ||
frame.Run == null ||
frame.Run.Zones == null ||
frame.Run.Zones.Count == 0)
var frame = LatestDaemonFrame(stateBoot);
if (frame == null)
{
Debug.LogWarning($"Cannot start Aetheria observer scene without an authoritative daemon frame at {AetheriaRuntimeDaemonFrameStore.GetFramePath(stateBoot.StateFilePath)}.");
Debug.LogWarning($"Cannot start Aetheria observer scene without an authoritative daemon frame in {stateBoot.StateFilePath}.");
return false;
}
@ -146,19 +144,25 @@ public class MainMenu : MonoBehaviour
return AetheriaRuntimeStateBoot.Inspect(ActionGameManager.GameDataDirectory);
}
private static AetheriaRuntimeDaemonFrameDocument LatestDaemonFrame(AetheriaRuntimeStateBootReport stateBoot)
private AetheriaRuntimeDaemonFrameDocument LatestDaemonFrame(AetheriaRuntimeStateBootReport stateBoot)
{
if (!AetheriaRuntimeStateReader.TryReadDaemonFrame(stateBoot.StateFilePath, out var frame) ||
frame == null ||
!frame.IsAuthoritative ||
frame.Run == null ||
frame.Run.Zones == null ||
frame.Run.Zones.Count == 0)
if (!stateBoot.SupportsLocalStateFileRead || !stateBoot.StateFileExists)
{
return null;
}
return frame;
try
{
return ResolveVerseClient(stateBoot)
.GetLatestAuthoritativeRunFrameAsync()
.GetAwaiter()
.GetResult();
}
catch (Exception ex)
{
Debug.LogError($"Failed to read authoritative Aetheria daemon frame for the main menu: {ex}");
return null;
}
}
private static AetheriaRuntimePlayerSettingsSnapshot LatestPlayerSettings(AetheriaRuntimeStateBootReport stateBoot)
@ -454,8 +458,33 @@ public class MainMenu : MonoBehaviour
return true;
}
private AetheriaRuntimeVerseClient ResolveVerseClient(AetheriaRuntimeStateBootReport stateBoot)
{
var statePath = stateBoot.StateFilePath;
if (_verseClient != null && string.Equals(_verseClientStatePath, statePath, StringComparison.Ordinal))
{
return _verseClient;
}
DisposeVerseClient();
_verseClient = AetheriaRuntimeVerseClient
.OpenAsync(statePath, "unity-main-menu", startServer: false, pullOnOpen: true)
.GetAwaiter()
.GetResult();
_verseClientStatePath = statePath;
return _verseClient;
}
private void DisposeVerseClient()
{
_verseClient?.Dispose();
_verseClient = null;
_verseClientStatePath = null;
}
private void OnDestroy()
{
DisposeVerseClient();
if (_menuSurfaceDocument != null)
{
Destroy(_menuSurfaceDocument.gameObject);

View file

@ -265,6 +265,23 @@ namespace GameCult.Aetheria.State.Verse
AetheriaRuntimeDaemonSoaViewStore.GetViewPath(StatePath));
}
public async Task<AetheriaRuntimeDaemonFrameDocument?> GetLatestAuthoritativeRunFrameAsync()
{
ThrowIfDisposed();
var frame = await GetLatestFrameAsync().ConfigureAwait(false);
if (frame == null ||
!frame.IsAuthoritative ||
frame.Run == null ||
frame.Run.Zones == null ||
frame.Run.Zones.Count == 0)
{
return null;
}
return frame;
}
public Task<EveSurfaceState?> GetDaemonGameSurfaceAsync()
{
ThrowIfDisposed();