using System; using System.Collections.Generic; using GameCult.Mesh; using MessagePack; using EveSurfaceDocument = GameCult.Eve.Surface.EveSurfaceDocument; #nullable enable namespace GameCult.Aetheria.State.Verse { public enum AetheriaClientEveSurface { Game, GameTui, Editor, EditorTui } public sealed class AetheriaClientState : IDisposable { private readonly Func> _mapViewport; private readonly Func> _objectsViewport; private readonly Func> _gravityViewport; private readonly Func> _renderSplatsViewport; private readonly Func> _zoneDetails; private readonly Func> _zoneDetailsSurface; private readonly Func> _inventoryPanelSurface; private readonly Func> _inventoryDropdownSurface; private readonly Func> _mainMenuSurfaceDocument; private readonly Func> _selectedObject; private readonly Func> _inventory; private readonly Func> _starbridgePlayerSeat; private CultMeshReactiveDocument? _eveStateRefFrame; private CultMeshReactiveDocument? _eveStateRefHealth; private CultMeshReactiveDocument? _eveStateRefCommandBoundary; private CultMeshReactiveDocument? _eveStateRefCatalog; internal AetheriaClientState( CultMeshDocumentHandle providerAdvertisement, CultMeshDocumentHandle health, CultMeshDocumentHandle commandBoundary, CultMeshDocumentHandle assetManifest, CultMeshDocumentHandle authorityPolicy, CultMeshDocumentHandle daemonFrame, CultMeshDocumentHandle daemonSoaView, CultMeshDocumentHandle gameSurface, CultMeshDocumentHandle gameTuiSurface, CultMeshDocumentHandle editorSurface, CultMeshDocumentHandle editorTuiSurface, CultMeshDocumentHandle catalog, CultMeshDocumentHandle loadoutTemplates, CultMeshDocumentHandle playerSettings, CultMeshDocumentHandle verseHostSettings, CultMeshDocumentHandle currentZone, CultMeshDocumentHandle currentEntity, CultMeshDocumentHandle currentDocking, CultMeshDocumentHandle zoneContacts, CultMeshDocumentHandle stationRefit, CultMeshDocumentHandle sectorMap, CultMeshDocumentHandle zoneRender, Func> mapViewport, Func> objectsViewport, Func> gravityViewport, Func> renderSplatsViewport, Func> zoneDetails, Func> zoneDetailsSurface, Func> inventoryPanelSurface, Func> inventoryDropdownSurface, Func> mainMenuSurfaceDocument, Func> selectedObject, Func> inventory, CultMeshDocumentHandle starbridgeScenario, CultMeshDocumentHandle starbridgeSession, CultMeshDocumentHandle starbridgeSummary, Func> starbridgePlayerSeat) { ProviderAdvertisement = providerAdvertisement ?? throw new ArgumentNullException(nameof(providerAdvertisement)); Health = health ?? throw new ArgumentNullException(nameof(health)); CommandBoundary = commandBoundary ?? throw new ArgumentNullException(nameof(commandBoundary)); AssetManifest = assetManifest ?? throw new ArgumentNullException(nameof(assetManifest)); AuthorityPolicy = authorityPolicy ?? throw new ArgumentNullException(nameof(authorityPolicy)); DaemonFrame = daemonFrame ?? throw new ArgumentNullException(nameof(daemonFrame)); DaemonSoaView = daemonSoaView ?? throw new ArgumentNullException(nameof(daemonSoaView)); GameSurface = gameSurface ?? throw new ArgumentNullException(nameof(gameSurface)); GameTuiSurface = gameTuiSurface ?? throw new ArgumentNullException(nameof(gameTuiSurface)); EditorSurface = editorSurface ?? throw new ArgumentNullException(nameof(editorSurface)); EditorTuiSurface = editorTuiSurface ?? throw new ArgumentNullException(nameof(editorTuiSurface)); Catalog = catalog ?? throw new ArgumentNullException(nameof(catalog)); LoadoutTemplates = loadoutTemplates ?? throw new ArgumentNullException(nameof(loadoutTemplates)); PlayerSettings = playerSettings ?? throw new ArgumentNullException(nameof(playerSettings)); VerseHostSettings = verseHostSettings ?? throw new ArgumentNullException(nameof(verseHostSettings)); CurrentZone = currentZone ?? throw new ArgumentNullException(nameof(currentZone)); CurrentEntity = currentEntity ?? throw new ArgumentNullException(nameof(currentEntity)); CurrentDocking = currentDocking ?? throw new ArgumentNullException(nameof(currentDocking)); ZoneContacts = zoneContacts ?? throw new ArgumentNullException(nameof(zoneContacts)); StationRefit = stationRefit ?? throw new ArgumentNullException(nameof(stationRefit)); SectorMap = sectorMap ?? throw new ArgumentNullException(nameof(sectorMap)); ZoneRender = zoneRender ?? throw new ArgumentNullException(nameof(zoneRender)); _mapViewport = mapViewport ?? throw new ArgumentNullException(nameof(mapViewport)); _objectsViewport = objectsViewport ?? throw new ArgumentNullException(nameof(objectsViewport)); _gravityViewport = gravityViewport ?? throw new ArgumentNullException(nameof(gravityViewport)); _renderSplatsViewport = renderSplatsViewport ?? throw new ArgumentNullException(nameof(renderSplatsViewport)); _zoneDetails = zoneDetails ?? throw new ArgumentNullException(nameof(zoneDetails)); _zoneDetailsSurface = zoneDetailsSurface ?? throw new ArgumentNullException(nameof(zoneDetailsSurface)); _inventoryPanelSurface = inventoryPanelSurface ?? throw new ArgumentNullException(nameof(inventoryPanelSurface)); _inventoryDropdownSurface = inventoryDropdownSurface ?? throw new ArgumentNullException(nameof(inventoryDropdownSurface)); _mainMenuSurfaceDocument = mainMenuSurfaceDocument ?? throw new ArgumentNullException(nameof(mainMenuSurfaceDocument)); _selectedObject = selectedObject ?? throw new ArgumentNullException(nameof(selectedObject)); _inventory = inventory ?? throw new ArgumentNullException(nameof(inventory)); StarbridgeScenario = starbridgeScenario ?? throw new ArgumentNullException(nameof(starbridgeScenario)); StarbridgeSession = starbridgeSession ?? throw new ArgumentNullException(nameof(starbridgeSession)); StarbridgeSummary = starbridgeSummary ?? throw new ArgumentNullException(nameof(starbridgeSummary)); _starbridgePlayerSeat = starbridgePlayerSeat ?? throw new ArgumentNullException(nameof(starbridgePlayerSeat)); } public CultMeshDocumentHandle ProviderAdvertisement { get; } public CultMeshDocumentHandle Health { get; } public CultMeshDocumentHandle CommandBoundary { get; } public CultMeshDocumentHandle AssetManifest { get; } public CultMeshDocumentHandle AuthorityPolicy { get; } public CultMeshDocumentHandle DaemonFrame { get; } public CultMeshDocumentHandle DaemonSoaView { get; } public CultMeshDocumentHandle Catalog { get; } public CultMeshDocumentHandle LoadoutTemplates { get; } public CultMeshDocumentHandle GameSurface { get; } public CultMeshDocumentHandle GameTuiSurface { get; } public CultMeshDocumentHandle EditorSurface { get; } public CultMeshDocumentHandle EditorTuiSurface { get; } public CultMeshDocumentHandle PlayerSettings { get; } public CultMeshDocumentHandle VerseHostSettings { get; } public CultMeshDocumentHandle CurrentZone { get; } public CultMeshDocumentHandle CurrentEntity { get; } public CultMeshDocumentHandle CurrentDocking { get; } public CultMeshDocumentHandle StarbridgeScenario { get; } public CultMeshDocumentHandle StarbridgeSession { get; } public CultMeshDocumentHandle StarbridgeSummary { get; } public CultMeshDocumentHandle ZoneContacts { get; } public CultMeshDocumentHandle StationRefit { get; } public CultMeshDocumentHandle SectorMap { get; } public CultMeshDocumentHandle ZoneRender { get; } public static bool TryResolveEveSurface( string? surfaceId, out AetheriaClientEveSurface surface) { if (string.Equals(surfaceId, AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, StringComparison.Ordinal)) { surface = AetheriaClientEveSurface.Game; return true; } if (string.Equals(surfaceId, AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, StringComparison.Ordinal)) { surface = AetheriaClientEveSurface.GameTui; return true; } if (string.Equals(surfaceId, AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, StringComparison.Ordinal)) { surface = AetheriaClientEveSurface.Editor; return true; } if (string.Equals(surfaceId, AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, StringComparison.Ordinal)) { surface = AetheriaClientEveSurface.EditorTui; return true; } surface = default; return false; } public CultMeshDocumentHandle? EveSurfaceDocument( string? surfaceId) { if (!TryResolveEveSurface(surfaceId, out var surface)) return null; return surface switch { AetheriaClientEveSurface.Game => GameSurface, AetheriaClientEveSurface.GameTui => GameTuiSurface, AetheriaClientEveSurface.Editor => EditorSurface, AetheriaClientEveSurface.EditorTui => EditorTuiSurface, _ => throw new ArgumentOutOfRangeException(nameof(surface), surface, null) }; } public CultMeshDocumentHandle GameViewport( AetheriaRuntimeViewportBounds viewport) { return _mapViewport(viewport ?? new AetheriaRuntimeViewportBounds()); } public CultMeshDocumentHandle ObjectsViewport( AetheriaRuntimeViewportBounds viewport) { return _objectsViewport(viewport ?? new AetheriaRuntimeViewportBounds()); } public CultMeshDocumentHandle GravityViewport( AetheriaRuntimeViewportBounds viewport) { return _gravityViewport(viewport ?? new AetheriaRuntimeViewportBounds()); } public CultMeshDocumentHandle RenderSplatsViewport( AetheriaRuntimeViewportBounds viewport) { return _renderSplatsViewport(viewport ?? new AetheriaRuntimeViewportBounds()); } public CultMeshDocumentHandle ZoneDetails(int zoneIndex) { if (zoneIndex < 0) throw new ArgumentOutOfRangeException(nameof(zoneIndex), zoneIndex, "Aetheria zone index must be non-negative."); return _zoneDetails(zoneIndex); } public CultMeshDocumentHandle ZoneDetailsSurface(int zoneIndex) { if (zoneIndex < 0) throw new ArgumentOutOfRangeException(nameof(zoneIndex), zoneIndex, "Aetheria zone index must be non-negative."); return _zoneDetailsSurface(zoneIndex); } public CultMeshDocumentHandle InventoryPanelSurface( AetheriaRuntimeInventoryPanelSurfaceRequest request) { return _inventoryPanelSurface(request ?? new AetheriaRuntimeInventoryPanelSurfaceRequest()); } public CultMeshDocumentHandle InventoryDropdownSurface( AetheriaRuntimeInventoryDropdownSurfaceRequest request) { return _inventoryDropdownSurface(request ?? new AetheriaRuntimeInventoryDropdownSurfaceRequest()); } public CultMeshDocumentHandle MainMenuSurface( string surfaceId, bool canOpenRuntimeInputScreen, bool inGame) { if (string.IsNullOrWhiteSpace(surfaceId)) throw new ArgumentException("Main menu surface id must be non-empty.", nameof(surfaceId)); return _mainMenuSurfaceDocument(surfaceId, canOpenRuntimeInputScreen, inGame); } public CultMeshDocumentHandle SelectedObject(int entityIndex) { if (entityIndex < 0) throw new ArgumentOutOfRangeException(nameof(entityIndex), entityIndex, "Aetheria entity index must be non-negative."); return _selectedObject(entityIndex); } public CultMeshDocumentHandle Inventory(int entityIndex) { if (entityIndex < 0) throw new ArgumentOutOfRangeException(nameof(entityIndex), entityIndex, "Aetheria entity index must be non-negative."); return _inventory(entityIndex); } public CultMeshDocumentHandle StarbridgePlayerSeat(string seatId) { if (string.IsNullOrWhiteSpace(seatId)) throw new ArgumentException("Seat id must be non-empty.", nameof(seatId)); return _starbridgePlayerSeat(seatId); } public CultMeshStateRefResolver CreateEveSurfaceCultMeshStateRefResolver() { return AetheriaRuntimeStateRefResolver.CreateEveSurfaceCultMeshStateRefResolver( () => ReadOptionalReactive(ref _eveStateRefFrame, DaemonFrame), () => ReadOptionalReactive(ref _eveStateRefHealth, Health), () => ReadOptionalReactive(ref _eveStateRefCommandBoundary, CommandBoundary), () => ReadOptionalReactive(ref _eveStateRefCatalog, Catalog)); } private static TDocument? ReadOptionalReactive( ref CultMeshReactiveDocument? reactive, CultMeshDocumentHandle handle) where TDocument : class { try { reactive ??= handle.Reactive(); return reactive.Current; } catch (KeyNotFoundException) { return null; } catch (FormatterNotRegisteredException) { return null; } } public void Dispose() { _eveStateRefFrame?.Dispose(); _eveStateRefHealth?.Dispose(); _eveStateRefCommandBoundary?.Dispose(); _eveStateRefCatalog?.Dispose(); _eveStateRefFrame = null; _eveStateRefHealth = null; _eveStateRefCommandBoundary = null; _eveStateRefCatalog = null; } } }