Centralize sector map state sessions

This commit is contained in:
Meta Vens 2026-06-28 14:14:50 +01:00
commit 90630cbc31
6 changed files with 122 additions and 29 deletions

View file

@ -4546,13 +4546,13 @@ static void RequireSectorMapZoneDetailsUseEveSurface(string root)
"ProjectZoneDetailsSurfaceState(",
"AetheriaUnityRuntimeClientProvider.ResolveClient(",
".State",
".ReactiveSectorMap()",
".ObserveSectorMap()",
".Details",
".ReactiveZone(zoneIndex)",
".ObserveZone(zoneIndex)",
"_zoneDetails?.Current",
".Settings",
".ReactiveCatalog()",
".ReactivePlayer()",
".ObserveCatalog()",
".ObservePlayer()",
"AetheriaClient",
"AetheriaRuntimeZoneDetailsSurfaceCommands.TryRead(request, out var command)",
"AetheriaRuntimeZoneDetailsCommandKind.Close"
@ -7594,13 +7594,22 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root)
"SectorRenderer.cs"));
var requiredSectorRendererSharedDocumentSymbols = new[]
{
"CultMeshReactiveDocument<AetheriaRuntimeCatalogSnapshot> _catalog",
"CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument> _playerSettings",
"ResolveClient().State.ReactiveCatalog()",
"AetheriaRuntimeCatalogSession _catalog",
"AetheriaRuntimePlayerSettingsSession _playerSettings",
"AetheriaRuntimeSectorMapSession _sectorMap",
"AetheriaRuntimeCurrentZoneSession _currentZone",
"AetheriaRuntimeZoneDetailsSession _zoneDetails",
"ResolveClient().State.ObserveCatalog()",
".ObserveSectorMap()",
".Current",
".ObserveZone(zoneIndex)",
".Settings",
".ReactivePlayer()",
".ObservePlayer()",
"_catalog?.Dispose()",
"_playerSettings?.Dispose()",
"_sectorMap?.Dispose()",
"_currentZone?.Dispose()",
"_zoneDetails?.Dispose()",
"_catalog?.Current",
"_playerSettings?.Current",
"private void OnDestroy()"
@ -7615,6 +7624,28 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root)
string.Join(", ", missingSectorRendererSharedDocumentSymbols));
}
var forbiddenSectorRendererSharedDocumentSymbols = new[]
{
"CultMeshReactiveDocument<AetheriaRuntimeCatalogSnapshot> _catalog",
"CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument> _playerSettings",
"CultMeshReactiveDocument<AetheriaRuntimeSectorMapDocument> _sectorMap",
"CultMeshReactiveDocument<AetheriaRuntimeCurrentZoneDocument> _currentZone",
"CultMeshReactiveDocument<AetheriaRuntimeZoneDetailsDocument> _zoneDetails",
"ResolveClient().State.ReactiveCatalog()",
".ReactiveSectorMap()",
".ReactiveZone(zoneIndex)",
".ReactivePlayer()"
};
var sectorRendererRawDocumentHits = forbiddenSectorRendererSharedDocumentSymbols
.Where(symbol => sectorRenderer.Contains(symbol, StringComparison.Ordinal))
.ToArray();
if (sectorRendererRawDocumentHits.Length > 0)
{
throw new InvalidOperationException(
"SectorRenderer still owns raw map/catalog/settings CultMesh documents instead of managed sessions: " +
string.Join(", ", sectorRendererRawDocumentHits));
}
var zoneRenderer = File.ReadAllText(Path.Combine(
root,
"Assets",
@ -7663,6 +7694,7 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root)
"public AetheriaRuntimeSectorMapDocument LatestSectorMap()",
"public AetheriaRuntimeZoneContactsDocument LatestZoneContacts()",
"public AetheriaRuntimeCurrentZoneDocument LatestZone()",
"public AetheriaRuntimeCurrentZoneSession ObserveZone(",
"public AetheriaRuntimeCurrentEntityDocument LatestEntity()",
"public AetheriaRuntimeObjectsViewportDocument LatestObjects(AetheriaRuntimeRtsViewportBounds viewport)",
"public CultMeshReactiveDocument<AetheriaRuntimeObjectsViewportDocument> ReactiveObjects(",
@ -7670,7 +7702,8 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root)
"public AetheriaRuntimeRenderSplatsViewportDocument LatestRenderSplats(AetheriaRuntimeRtsViewportBounds viewport)",
"public CultMeshReactiveDocument<AetheriaRuntimeRenderSplatsViewportDocument> ReactiveRenderSplats(",
"public AetheriaRuntimeRenderSplatsViewportSession ObserveRenderSplats(",
"public AetheriaRuntimeZoneDetailsDocument LatestZone(int zoneIndex)"
"public AetheriaRuntimeZoneDetailsDocument LatestZone(int zoneIndex)",
"public AetheriaRuntimeZoneDetailsSession ObserveZone("
};
var missingClientSymbols = requiredClientSymbols
.Where(symbol => !clientState.Contains(symbol, StringComparison.Ordinal))
@ -13584,16 +13617,16 @@ static void RequireUnityObserverDoesNotTickLocalSimulation(string root)
!mapRenderer.Contains(".ObservePlayer()", StringComparison.Ordinal) ||
!sectorRenderer.Contains("AetheriaUnityRuntimeClientProvider.ResolveClient(", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".State", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".ReactiveSectorMap()", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".ObserveSectorMap()", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".Details", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".ReactiveZone(zoneIndex)", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".ObserveZone(zoneIndex)", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".Current", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".Settings", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".ReactiveCatalog()", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".ReactivePlayer()", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".ObserveCatalog()", StringComparison.Ordinal) ||
!sectorRenderer.Contains(".ObservePlayer()", StringComparison.Ordinal) ||
!sectorMap.Contains("AetheriaUnityRuntimeClientProvider.ResolveClient(", StringComparison.Ordinal) ||
!sectorMap.Contains(".State", StringComparison.Ordinal) ||
!sectorMap.Contains(".ReactiveSectorMap()", StringComparison.Ordinal) ||
!sectorMap.Contains(".ObserveSectorMap()", StringComparison.Ordinal) ||
!sectorRenderer.Contains("AetheriaRuntimeZoneDetailsSurfaceBuilder.ProjectDaemonZone(", StringComparison.Ordinal))
{
throw new InvalidOperationException(
@ -13607,6 +13640,13 @@ static void RequireUnityObserverDoesNotTickLocalSimulation(string root)
"Map and sector UI must not read the raw ObservedGalaxy projection directly.");
}
if (sectorMap.Contains("CultMeshReactiveDocument<AetheriaRuntimeSectorMapDocument> _sectorMapDocument", StringComparison.Ordinal) ||
sectorMap.Contains(".ReactiveSectorMap()", StringComparison.Ordinal))
{
throw new InvalidOperationException(
"SectorMap still owns a raw sector-map CultMesh document instead of AetheriaRuntimeSectorMapSession.");
}
var requiredDaemonControlValidationSymbols = new[]
{
"case AetheriaRuntimeDaemonCommandKinds.SetTractorPower:",
@ -15315,7 +15355,9 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root)
"public AetheriaRuntimeVerseHostSettingsSession ObserveVerseHost(",
"public AetheriaRuntimeSectorMapSession ObserveSectorMap(",
"public AetheriaRuntimeObjectsViewportSession ObserveObjects(",
"public AetheriaRuntimeRenderSplatsViewportSession ObserveRenderSplats("
"public AetheriaRuntimeRenderSplatsViewportSession ObserveRenderSplats(",
"public AetheriaRuntimeCurrentZoneSession ObserveZone(",
"public AetheriaRuntimeZoneDetailsSession ObserveZone("
};
var missingManagedStateAccessSymbols = requiredManagedStateAccessSymbols
.Where(symbol => !aetheriaClientState.Contains(symbol, StringComparison.Ordinal))

View file

@ -210,6 +210,8 @@ public class DaemonRuntimeDocumentTests
using var playerSettingsSession = client.State.Settings.ObservePlayer();
using var verseHostSettingsSession = client.State.Settings.ObserveVerseHost();
using var zoneContactsSession = client.State.ObserveZoneContacts();
using var currentZoneSession = client.State.Current.ObserveZone();
using var zoneDetailsSession = client.State.Details.ObserveZone(0);
using var objectsViewportSession = client.State.Viewports.ObserveObjects(viewport);
using var renderSplatsViewportSession = client.State.Viewports.ObserveRenderSplats(viewport);
using var playerHud = client.State.ObservePlayerHud();
@ -296,8 +298,10 @@ public class DaemonRuntimeDocumentTests
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ObjectsViewport, objectsViewportSession.Current.Schema);
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.RenderSplatsViewport, renderSplatsViewportSession.Current.Schema);
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ZoneContacts, zoneContactsSession.Current.Schema);
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.CurrentZone, currentZoneSession.Current.Schema);
Assert.AreEqual("Player", objectsViewport.Objects.FirstOrDefault()?.DisplayName);
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ZoneDetails, zoneDetails.Schema);
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ZoneDetails, zoneDetailsSession.Current.Schema);
Assert.AreEqual(0, zoneDetails.ZoneIndex);
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Inventory, inventory.Schema);
Assert.AreEqual("zone.0.entity.0", inventory.EntityKey);

View file

@ -2,7 +2,6 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using GameCult.Mesh;
using GameCult.Aetheria.State.Verse;
using TMPro;
using UniRx;
@ -53,7 +52,7 @@ public class SectorMap : MonoBehaviour
private readonly Queue<IEnumerable<int>> _queuedZoneReveals = new Queue<IEnumerable<int>>();
private readonly Dictionary<int, AetheriaRuntimeSectorMapZone> _zonesByIndex =
new Dictionary<int, AetheriaRuntimeSectorMapZone>();
private CultMeshReactiveDocument<AetheriaRuntimeSectorMapDocument> _sectorMapDocument;
private AetheriaRuntimeSectorMapSession _sectorMapDocument;
private AetheriaRuntimeSectorMapDocument _sectorMap;
private bool _sectorMapLoaded;
@ -223,7 +222,7 @@ public class SectorMap : MonoBehaviour
{
_sectorMapDocument ??= ResolveClient()
.State
.ReactiveSectorMap();
.ObserveSectorMap();
_sectorMap = _sectorMapDocument.Current;
if (_sectorMapLoaded)

View file

@ -3,7 +3,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using GameCult.Mesh;
using GameCult.Aetheria.EveRuntime;
using GameCult.Aetheria.State.Verse;
using GameCult.Eve.Surface;
@ -47,12 +46,12 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
private float _sectorCameraDepth;
private UIDocument _zoneDetailsSurfaceDocument;
private string _clientStatePath = "";
private CultMeshReactiveDocument<AetheriaRuntimeCatalogSnapshot> _catalog;
private CultMeshReactiveDocument<AetheriaRuntimePlayerSettingsDocument> _playerSettings;
private CultMeshReactiveDocument<AetheriaRuntimeSectorMapDocument> _sectorMap;
private CultMeshReactiveDocument<AetheriaRuntimeCurrentZoneDocument> _currentZone;
private AetheriaRuntimeCatalogSession _catalog;
private AetheriaRuntimePlayerSettingsSession _playerSettings;
private AetheriaRuntimeSectorMapSession _sectorMap;
private AetheriaRuntimeCurrentZoneSession _currentZone;
private int _zoneDetailsIndex = -1;
private CultMeshReactiveDocument<AetheriaRuntimeZoneDetailsDocument> _zoneDetails;
private AetheriaRuntimeZoneDetailsSession _zoneDetails;
private readonly AetheriaEveUnitySurfaceChrome _zoneDetailsSurfaceChrome = new AetheriaEveUnitySurfaceChrome
{
RootAlignItems = Align.FlexEnd,
@ -176,7 +175,7 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
{
_sectorMap ??= ResolveClient()
.State
.ReactiveSectorMap();
.ObserveSectorMap();
var sectorMap = _sectorMap.Current;
return (sectorMap?.Zones ?? Array.Empty<AetheriaRuntimeSectorMapZone>())
.FirstOrDefault(zone => zone.ZoneIndex == zoneIndex);
@ -206,7 +205,7 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
var nextZoneDetails = ResolveClient()
.State
.Details
.ReactiveZone(zoneIndex);
.ObserveZone(zoneIndex);
_zoneDetails?.Dispose();
_zoneDetailsIndex = zoneIndex;
_zoneDetails = nextZoneDetails;
@ -232,7 +231,7 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
try
{
_catalog = ResolveClient().State.ReactiveCatalog();
_catalog = ResolveClient().State.ObserveCatalog();
}
catch (Exception ex)
{
@ -252,7 +251,7 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
_playerSettings = ResolveClient()
.State
.Settings
.ReactivePlayer();
.ObservePlayer();
}
catch (Exception ex)
{
@ -325,7 +324,7 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS
_currentZone ??= ResolveClient()
.State
.Current
.ReactiveZone();
.ObserveZone();
}
catch (Exception ex)
{

View file

@ -892,6 +892,12 @@ namespace GameCult.Aetheria.State.Verse
return Zone.Reactive(options);
}
public AetheriaRuntimeCurrentZoneSession ObserveZone(
CultMeshReactiveDocumentOptions? options = null)
{
return new AetheriaRuntimeCurrentZoneSession(ReactiveZone(options));
}
public Task<AetheriaRuntimeCurrentEntityDocument> LatestEntityAsync()
{
return Entity.LatestAsync();
@ -1193,6 +1199,13 @@ namespace GameCult.Aetheria.State.Verse
return Zone(zoneIndex).Reactive(options);
}
public AetheriaRuntimeZoneDetailsSession ObserveZone(
int zoneIndex,
CultMeshReactiveDocumentOptions? options = null)
{
return new AetheriaRuntimeZoneDetailsSession(ReactiveZone(zoneIndex, options));
}
public CultMeshDocumentHandle<AetheriaRuntimeSelectedObjectDocument> SelectedObject(int entityIndex)
{
return _selectedObject(entityIndex);

View file

@ -95,6 +95,42 @@ namespace GameCult.Aetheria.State.Verse
}
}
public sealed class AetheriaRuntimeCurrentZoneSession : IDisposable
{
private readonly CultMeshReactiveDocument<AetheriaRuntimeCurrentZoneDocument> _currentZone;
public AetheriaRuntimeCurrentZoneSession(
CultMeshReactiveDocument<AetheriaRuntimeCurrentZoneDocument> currentZone)
{
_currentZone = currentZone ?? throw new ArgumentNullException(nameof(currentZone));
}
public AetheriaRuntimeCurrentZoneDocument? Current => _currentZone.Current;
public void Dispose()
{
_currentZone.Dispose();
}
}
public sealed class AetheriaRuntimeZoneDetailsSession : IDisposable
{
private readonly CultMeshReactiveDocument<AetheriaRuntimeZoneDetailsDocument> _zoneDetails;
public AetheriaRuntimeZoneDetailsSession(
CultMeshReactiveDocument<AetheriaRuntimeZoneDetailsDocument> zoneDetails)
{
_zoneDetails = zoneDetails ?? throw new ArgumentNullException(nameof(zoneDetails));
}
public AetheriaRuntimeZoneDetailsDocument? Current => _zoneDetails.Current;
public void Dispose()
{
_zoneDetails.Dispose();
}
}
public sealed class AetheriaRuntimeObjectsViewportSession : IDisposable
{
private readonly CultMeshReactiveDocument<AetheriaRuntimeObjectsViewportDocument> _objectsViewport;