Centralize player HUD state access

This commit is contained in:
Meta Vens 2026-06-28 13:37:15 +01:00
commit 43f92f2b7b
7 changed files with 108 additions and 65 deletions

View file

@ -2556,13 +2556,13 @@ static void RequireDaemonRenderQueryAuthority(string root)
var requiredSchematicHudSymbols = new[]
{
"private CultMeshReactiveDocument<AetheriaRuntimeCurrentEntityDocument> _currentEntity;",
"private AetheriaRuntimePlayerHudSession _playerHud;",
"ResolvePlayerHud()",
"ResolveCurrentEntityHudStatus()",
"AetheriaUnityRuntimeClientProvider.ResolveClient(",
".Current",
".ReactiveEntity()",
"_currentEntity?.Current?.Hud",
"_currentEntity?.Dispose()",
"ResolveClient().State.ObservePlayerHud()",
"return ResolvePlayerHud()?.Hud ?? new AetheriaRuntimeCurrentEntityHudStatus();",
"_playerHud?.Dispose()",
"hud.OverrideShutdown",
"hud.HeatsinksEnabled",
"hud.Heatstroke",
@ -7266,16 +7266,11 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root)
"SchematicDisplay.cs"));
var requiredSchematicDisplaySymbols = new[]
{
"CultMeshReactiveDocument<AetheriaRuntimeCatalogSnapshot> _catalog",
"CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument> _playerSettings",
"ResolveClient().State.ReactiveCatalog()",
".Settings",
".ReactivePlayer()",
"_catalog?.Dispose()",
"_playerSettings?.Dispose()",
"_catalog?.Current",
"ResolveCatalog()?.FindItem(item, x => x.ItemKey)",
"_playerSettings?.Current",
"AetheriaRuntimePlayerHudSession _playerHud",
"ResolveClient().State.ObservePlayerHud()",
"_playerHud?.Dispose()",
"ResolvePlayerHud()?.Catalog?.FindItem(item, x => x.ItemKey)",
"ResolvePlayerHud()?.PlayerSettings",
"private void OnDestroy()"
};
var missingSchematicDisplaySymbols = requiredSchematicDisplaySymbols
@ -7284,10 +7279,29 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root)
if (missingSchematicDisplaySymbols.Length > 0)
{
throw new InvalidOperationException(
"SchematicDisplay should bind shared catalog/settings through managed reactive Aetheria documents with HUD lifetime disposal: " +
"SchematicDisplay should bind shared catalog/settings/current-entity HUD through one managed Aetheria player HUD session: " +
string.Join(", ", missingSchematicDisplaySymbols));
}
var forbiddenSchematicDisplaySymbols = new[]
{
"CultMeshReactiveDocument<AetheriaRuntimeCatalogSnapshot> _catalog",
"CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument> _playerSettings",
"CultMeshReactiveDocument<AetheriaRuntimeCurrentEntityDocument> _currentEntity",
".State.ReactiveCatalog()",
".ReactivePlayer()",
".ReactiveEntity()"
};
var schematicDisplayHits = forbiddenSchematicDisplaySymbols
.Where(symbol => schematicDisplay.Contains(symbol, StringComparison.Ordinal))
.ToArray();
if (schematicDisplayHits.Length > 0)
{
throw new InvalidOperationException(
"SchematicDisplay still owns raw player HUD CultMesh documents instead of AetheriaRuntimePlayerHudSession: " +
string.Join(", ", schematicDisplayHits));
}
var mapRenderer = File.ReadAllText(Path.Combine(
root,
"Assets",
@ -7725,6 +7739,7 @@ static void RequireAetheriaManagedStateAccessorsCoverDomainDocuments(string root
"public CultMeshReactiveDocument<AetheriaRuntimeDaemonSoaViewDocument> ReactiveDaemonSoaView(",
"public AetheriaRuntimeObservedDaemonState? LatestObservedDaemon()",
"public AetheriaRuntimeObservedDockingState? CurrentDocking(",
"public AetheriaRuntimePlayerHudSession ObservePlayerHud(",
"public AetheriaRuntimeLoadoutTemplatesDocument LatestLoadoutTemplates()",
"public AetheriaRuntimeStationRefitDocument LatestStationRefit()",
"public AetheriaRuntimeZoneRenderDocument LatestZoneRender()",

View file

@ -205,6 +205,7 @@ public class DaemonRuntimeDocumentTests
.Reactive<AetheriaRuntimeZoneRenderDocument>();
var observed = client.State.LatestObservedDaemon();
var observedAuthoritativeFrame = client.State.LatestDaemonFrame();
using var playerHud = client.State.ObservePlayerHud();
var gameSurface = client.State.LatestGameSurface();
var gameTuiSurface = client.State.LatestGameTuiSurface();
var editorSurface = client.State.LatestEditorSurface();
@ -289,6 +290,9 @@ public class DaemonRuntimeDocumentTests
Assert.AreEqual("zone.0.entity.0", currentEntity.EntityKey);
Assert.AreEqual(0, currentEntity.EntityIndex);
Assert.AreEqual("Player", currentEntity.Entity?.DisplayName);
Assert.AreEqual(currentEntity.EntityKey, playerHud.CurrentEntity.EntityKey);
Assert.AreEqual(AetheriaRuntimePlayerSettingsDocument.SchemaId, playerHud.PlayerSettings.Schema);
Assert.AreSame(playerHud.Hud, playerHud.CurrentEntity.Hud);
Assert.AreEqual(currentEntity.EntityKey, currentEntityReactive.Current.EntityKey);
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ZoneRender, zoneRenderReactive.Current.Schema);
Assert.AreEqual(currentEntity.EntityKey, currentEntityByType.EntityKey);

View file

@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using GameCult.Aetheria.State.Verse;
using GameCult.Mesh;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
@ -70,9 +69,7 @@ public class SchematicDisplay : MonoBehaviour
private SchematicDisplayItem[] _schematicItems;
private AetherDrive _aetherDrive;
private string _clientStatePath = "";
private CultMeshReactiveDocument<AetheriaRuntimeCatalogSnapshot> _catalog;
private CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument> _playerSettings;
private CultMeshReactiveDocument<AetheriaRuntimeCurrentEntityDocument> _currentEntity;
private AetheriaRuntimePlayerHudSession _playerHud;
private AetheriaRuntimeDaemonRenderSettings? _renderSettings;
private bool _enemy;
@ -316,64 +313,34 @@ public class SchematicDisplay : MonoBehaviour
private AetheriaRuntimeCatalogItem FindTypedItem(ItemInstance item)
{
return ResolveCatalog()?.FindItem(item, x => x.ItemKey);
return ResolvePlayerHud()?.Catalog?.FindItem(item, x => x.ItemKey);
}
private AetheriaRuntimeCatalogSnapshot ResolveCatalog()
private AetheriaRuntimePlayerHudSession ResolvePlayerHud()
{
if (_catalog != null)
return _catalog.Current;
if (_playerHud != null)
return _playerHud;
try
{
_catalog = ResolveClient().State.ReactiveCatalog();
_playerHud = ResolveClient().State.ObservePlayerHud();
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to bind Aetheria runtime catalog for schematic display: {ex.Message}");
Debug.LogWarning($"Failed to bind Aetheria player HUD state for schematic display: {ex.Message}");
}
return _catalog?.Current;
return _playerHud;
}
private AetheriaRuntimePlayerSettingsDocument ResolvePlayerSettings()
{
if (_playerSettings != null)
return _playerSettings.Current;
try
{
_playerSettings = ResolveClient()
.State
.Settings
.ReactivePlayer();
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to bind Aetheria player settings for schematic display: {ex.Message}");
}
return _playerSettings?.Current;
return ResolvePlayerHud()?.PlayerSettings;
}
private AetheriaRuntimeCurrentEntityHudStatus ResolveCurrentEntityHudStatus()
{
if (_currentEntity == null)
{
try
{
_currentEntity = ResolveClient()
.State
.Current
.ReactiveEntity();
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to bind Aetheria current entity HUD status: {ex.Message}");
}
}
return _currentEntity?.Current?.Hud ?? new AetheriaRuntimeCurrentEntityHudStatus();
return ResolvePlayerHud()?.Hud ?? new AetheriaRuntimeCurrentEntityHudStatus();
}
private AetheriaClient ResolveClient()
@ -418,12 +385,8 @@ public class SchematicDisplay : MonoBehaviour
private void ClearClientCaches()
{
_catalog?.Dispose();
_playerSettings?.Dispose();
_currentEntity?.Dispose();
_catalog = null;
_playerSettings = null;
_currentEntity = null;
_playerHud?.Dispose();
_playerHud = null;
}
private void OnDestroy()

View file

@ -75,6 +75,7 @@
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimePlayerSettingsCommands.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaControl.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeDaemonStateRefs.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimePlayerHudState.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeMainMenuSurfaceBuilder.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeRenderSplatDocuments.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeInputSettingsSurfaceBuilder.cs" />

View file

@ -299,6 +299,27 @@ namespace GameCult.Aetheria.State.Verse
: null;
}
public AetheriaRuntimePlayerHudSession ObservePlayerHud(
CultMeshReactiveDocumentOptions? options = null)
{
var catalog = ReactiveCatalog(options);
CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument>? playerSettings = null;
CultMeshReactiveDocument<AetheriaRuntimeCurrentEntityDocument>? currentEntity = null;
try
{
playerSettings = Settings.ReactivePlayer(options);
currentEntity = Current.ReactiveEntity(options);
return new AetheriaRuntimePlayerHudSession(catalog, playerSettings, currentEntity);
}
catch
{
catalog.Dispose();
playerSettings?.Dispose();
currentEntity?.Dispose();
throw;
}
}
private CultMeshReactiveDocument<AetheriaRuntimeDaemonSoaViewDocument>? TryReactiveDaemonSoaView(
CultMeshReactiveDocumentOptions? options)
{

View file

@ -0,0 +1,37 @@
using System;
using GameCult.Mesh;
#nullable enable
namespace GameCult.Aetheria.State.Verse
{
public sealed class AetheriaRuntimePlayerHudSession : IDisposable
{
private readonly CultMeshReactiveDocument<AetheriaRuntimeCatalogSnapshot> _catalog;
private readonly CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument> _playerSettings;
private readonly CultMeshReactiveDocument<AetheriaRuntimeCurrentEntityDocument> _currentEntity;
public AetheriaRuntimePlayerHudSession(
CultMeshReactiveDocument<AetheriaRuntimeCatalogSnapshot> catalog,
CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument> playerSettings,
CultMeshReactiveDocument<AetheriaRuntimeCurrentEntityDocument> currentEntity)
{
_catalog = catalog ?? throw new ArgumentNullException(nameof(catalog));
_playerSettings = playerSettings ?? throw new ArgumentNullException(nameof(playerSettings));
_currentEntity = currentEntity ?? throw new ArgumentNullException(nameof(currentEntity));
}
public AetheriaRuntimeCatalogSnapshot? Catalog => _catalog.Current;
public AetheriaRuntimePlayerSettingsDocument? PlayerSettings => _playerSettings.Current;
public AetheriaRuntimeCurrentEntityDocument? CurrentEntity => _currentEntity.Current;
public AetheriaRuntimeCurrentEntityHudStatus Hud =>
CurrentEntity?.Hud ?? new AetheriaRuntimeCurrentEntityHudStatus();
public void Dispose()
{
_catalog.Dispose();
_playerSettings.Dispose();
_currentEntity.Dispose();
}
}
}

View file

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0525c14d10a54fd2b92fbf9984a41dc0