using CultMath; using GameCult.Aetheria.State.Verse; using GameCult.Mesh; using NUnit.Framework; using System; using System.Collections.Generic; using System.IO; using System.IO.MemoryMappedFiles; using System.Linq; using EveCommandTemplate = GameCult.Eve.Surface.EveCommandTemplate; using EveStyleToken = GameCult.Eve.Surface.EveStyleToken; using EveSurfaceCommandRequest = GameCult.Eve.Surface.EveSurfaceCommandRequest; using EveSurfaceComponent = GameCult.Eve.Surface.EveSurfaceComponent; using EveSurfaceDocument = GameCult.Eve.Surface.EveSurfaceDocument; using EveSurfaceTree = GameCult.Eve.Surface.EveSurfaceTree; public class DaemonRuntimeDocumentTests { [Test] public void FrameFactoryMarksDaemonAsAuthoritativeStateSource() { var run = new AetheriaRuntimeRunCheckpointCommit { RunId = "run-1", CurrentZoneIndex = 3, CurrentEntityKey = "entity:player" }; var frame = AetheriaRuntimeDaemonFrameDocument.Create( run, "ymir-daemon", "session-1", 42, 12.5, 0.02); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Frame, frame.Schema); Assert.AreEqual("ymir-daemon", frame.DaemonId); Assert.AreEqual("session-1", frame.SessionId); Assert.AreEqual(42, frame.FrameId); Assert.AreEqual(12.5, frame.SimulationTimeSeconds); Assert.AreEqual(0.02, frame.FixedDeltaSeconds); Assert.IsTrue(frame.IsAuthoritative); Assert.AreEqual("daemon", frame.StateSource); Assert.AreSame(run, frame.Run); Assert.AreEqual("entity:player", frame.Run.CurrentEntityKey); Assert.IsNotEmpty(frame.PublishedAtUtc); } [Test] public void CommandFactoryPreservesClientObservedFrame() { var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetTarget, "codex", "session-1", 42, "entity:player"); command.TargetEntityKey = "entity:pirate"; Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Command, command.Schema); Assert.AreEqual(AetheriaRuntimeDaemonCommandKinds.SetTarget, command.Kind); Assert.AreEqual("codex", command.ClientId); Assert.AreEqual("session-1", command.SessionId); Assert.AreEqual(42, command.ObservedFrameId); Assert.AreEqual("entity:player", command.ActorEntityKey); Assert.AreEqual("entity:pirate", command.TargetEntityKey); Assert.IsNotEmpty(command.CommandId); Assert.IsNotEmpty(command.IssuedAtUtc); } [Test] public void CommandDocumentRoundTripsThroughStateNode() { var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.FireWeaponGroup, "bifrost", "session-2", 99, "entity:player"); command.WeaponGroup = 2; var result = AetheriaRuntimeDaemonOperations.Execute( new AetheriaRuntimeRunCheckpointCommit(), new[] { command }); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Command, command.Schema); Assert.AreEqual(AetheriaRuntimeDaemonCommandKinds.FireWeaponGroup, command.Kind); Assert.AreEqual("bifrost", command.ClientId); Assert.AreEqual("session-2", command.SessionId); Assert.AreEqual(99, command.ObservedFrameId); Assert.AreEqual("entity:player", command.ActorEntityKey); Assert.AreEqual(2, command.WeaponGroup); CollectionAssert.Contains(result.AppliedCommandIds, command.CommandId); } [Test] public void FrameStorePublishesLatestDaemonFrame() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-frame-store-tests", Path.GetRandomFileName(), "state.cc"); var frame = AetheriaRuntimeDaemonFrameDocument.Create( new AetheriaRuntimeRunCheckpointCommit { RunId = "run-2", CurrentZoneIndex = 7, CurrentEntityKey = "entity:ship" }, "aetheria-daemon", "session-3", 123, 45.5, 0.016); var framePath = AetheriaRuntimeDaemonFrameStore.PublishFrame(statePath, frame); var read = AetheriaRuntimeDaemonFrameStore.TryReadFrame(statePath, out var stored); Assert.IsTrue(read); Assert.AreEqual(AetheriaRuntimeStateBoundary.GetDaemonFramePath(statePath), framePath); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Frame, stored.Schema); Assert.AreEqual("aetheria-daemon", stored.DaemonId); Assert.AreEqual("session-3", stored.SessionId); Assert.AreEqual(123, stored.FrameId); Assert.IsTrue(stored.IsAuthoritative); Assert.AreEqual("daemon", stored.StateSource); Assert.AreEqual("run-2", stored.Run.RunId); Assert.AreEqual(7, stored.Run.CurrentZoneIndex); Assert.AreEqual("entity:ship", stored.Run.CurrentEntityKey); } [Test] public void FrameStoreReportsMissingFrame() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-frame-store-tests", Path.GetRandomFileName(), "missing-state.cc"); Assert.IsFalse(AetheriaRuntimeDaemonFrameStore.TryReadFrame(statePath, out _)); } [Test] public void AetheriaClientStateFacadeReadsProjectedDocumentsThroughCultMesh() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-client-state-facade-tests", Path.GetRandomFileName(), "state.cc"); var frame = AetheriaRuntimeDaemonFrameDocument.Create( RunWithTwoEntities(), "daemon", "session-state", 7, 1.25, 0.02); PublishLatestFrameThroughVerseClient(statePath, frame); using var client = AetheriaClient .OpenAsync(statePath, "unity-test", pullOnOpen: true) .GetAwaiter() .GetResult(); var currentEntity = client.Aetheria().Current.Entity.LatestAsync().GetAwaiter().GetResult(); var latestFrame = client.Aetheria().LatestFrame.LatestAsync().GetAwaiter().GetResult(); var catalog = client.Aetheria().Catalog.LatestAsync().GetAwaiter().GetResult(); var playerSettings = client.Aetheria().Settings.Player.LatestAsync().GetAwaiter().GetResult(); var verseHostSettings = client.Aetheria().Settings.VerseHost.LatestAsync().GetAwaiter().GetResult(); var currentEntityByType = client.Aetheria() .LatestAsync() .GetAwaiter() .GetResult(); var latestFrameByType = client.Aetheria() .LatestAsync() .GetAwaiter() .GetResult(); var viewport = new AetheriaRuntimeRtsViewportBounds { MinX = -100, MinY = -100, MaxX = 100, MaxY = 100 }; var objectsViewport = client.Aetheria() .Viewports .Objects(viewport) .LatestAsync() .GetAwaiter() .GetResult(); var zoneDetails = client.Aetheria() .Details .Zone(0) .LatestAsync() .GetAwaiter() .GetResult(); var inventory = client.Aetheria() .Details .Inventory(0) .LatestAsync() .GetAwaiter() .GetResult(); var currentEntityFromClientType = client .LatestAsync() .GetAwaiter() .GetResult(); using var currentEntityReactive = client .ReactiveAsync() .GetAwaiter() .GetResult(); using var zoneRenderReactive = client.State .Reactive(); var legacyCurrentEntity = client.CurrentEntityAsync().GetAwaiter().GetResult(); var legacyObserved = client.ObserveAsync().GetAwaiter().GetResult(); var legacyAuthoritativeFrame = client.LatestAuthoritativeRunFrameAsync().GetAwaiter().GetResult(); var legacyGameSurface = client.DaemonGameSurfaceAsync().GetAwaiter().GetResult(); var legacyGameTuiSurface = client.DaemonGameTuiSurfaceAsync().GetAwaiter().GetResult(); var legacyEditorSurface = client.DaemonEditorSurfaceAsync().GetAwaiter().GetResult(); var legacyEditorTuiSurface = client.DaemonEditorTuiSurfaceAsync().GetAwaiter().GetResult(); var dockingState = client.Aetheria() .DockingState .LatestAsync() .GetAwaiter() .GetResult(); Assert.AreEqual("aetheria.current.entity", client.State.Current.Entity.DocumentId); Assert.AreSame(client.State.Current.Entity, client.State.Document()); Assert.AreSame(client.State.Catalog, client.Document()); Assert.AreSame(client.State.ZoneRender, client.Document()); Assert.AreSame(client.State.LatestFrame, client.Document()); Assert.AreSame(client.State.Daemon.LatestFrame, client.State.LatestFrame); Assert.AreSame(client.State.Daemon.LatestSoaView, client.State.LatestSoaView); Assert.AreSame( client.State.Daemon.ProviderAdvertisement, client.Document()); Assert.AreSame(client.State.Daemon.Health, client.Document()); Assert.AreSame( client.State.Daemon.CommandBoundary, client.Document()); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, client.State.Daemon.GameSurface.DocumentId); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, client.State.Daemon.GameTuiSurface.DocumentId); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, client.State.Daemon.EditorSurface.DocumentId); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, client.State.Daemon.EditorTuiSurface.DocumentId); Assert.AreSame(client.State.Settings.Player, client.Document()); Assert.AreSame(client.State.Settings.VerseHost, client.Document()); Assert.AreSame( client.State.Current.Entity, client.State.DocumentBySchema(AetheriaRuntimeDaemonSchemas.CurrentEntity)); Assert.AreSame( client.State.ZoneContacts, client.DocumentBySchema("gamecult.aetheria.zone_contacts")); Assert.AreEqual( typeof(AetheriaRuntimeCurrentEntityDocument), client.DocumentBySchema(AetheriaRuntimeDaemonSchemas.CurrentEntity).DocumentType); Assert.IsTrue(client.State.TryGetDocument(out var sectorMapDocument)); Assert.AreSame(client.State.SectorMap, sectorMapDocument); Assert.IsTrue(client.State.TryGetDocumentBySchema( AetheriaRuntimeDaemonSchemas.SectorMap, out var sectorMapBySchema)); Assert.AreSame(client.State.SectorMap, sectorMapBySchema); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.CurrentEntity, currentEntity.Schema); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Frame, latestFrame.Schema); Assert.AreEqual(frame.FrameId, latestFrame.FrameId); Assert.AreEqual(frame.FrameId, latestFrameByType.FrameId); Assert.AreEqual(frame.FrameId, legacyObserved.Frame.FrameId); Assert.AreEqual(frame.FrameId, legacyAuthoritativeFrame.FrameId); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, legacyGameSurface.Surface.Id); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, legacyGameTuiSurface.Surface.Id); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, legacyEditorSurface.Surface.Id); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, legacyEditorTuiSurface.Surface.Id); Assert.AreEqual(AetheriaRuntimeCatalogSnapshot.SchemaId, client.State.Catalog.Sources.Last().SchemaId); Assert.GreaterOrEqual(catalog.Items.Count, 0); Assert.AreEqual(AetheriaRuntimePlayerSettingsDocument.SchemaId, playerSettings.Schema); Assert.AreEqual(AetheriaRuntimeVerseHostSettingsDocument.SchemaId, verseHostSettings.Schema); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ObjectsViewport, objectsViewport.Schema); Assert.AreEqual("Player", objectsViewport.Objects.FirstOrDefault()?.DisplayName); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ZoneDetails, zoneDetails.Schema); Assert.AreEqual(0, zoneDetails.ZoneIndex); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Inventory, inventory.Schema); Assert.AreEqual("zone.0.entity.0", inventory.EntityKey); Assert.AreEqual("zone.0.entity.0", currentEntity.EntityKey); Assert.AreEqual(0, currentEntity.EntityIndex); Assert.AreEqual("Player", currentEntity.Entity?.DisplayName); Assert.AreEqual(currentEntity.EntityKey, currentEntityReactive.Current.EntityKey); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ZoneRender, zoneRenderReactive.Current.Schema); Assert.AreEqual(currentEntity.EntityKey, currentEntityByType.EntityKey); Assert.AreEqual(currentEntity.EntityKey, currentEntityFromClientType.EntityKey); Assert.AreEqual(legacyCurrentEntity.EntityKey, currentEntity.EntityKey); Assert.AreEqual(currentEntity.EntityKey, dockingState.CurrentEntityKey); Assert.AreEqual("", dockingState.DockParentEntityKey); Assert.AreEqual(-1, dockingState.DockingBayIndex); Assert.IsTrue(client.State.Current.Entity.Sources.Any(source => source.SourceId == AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest.ToString())); Assert.IsTrue(client.State.StationRefit.Sources.Any(source => source.SourceId == "catalog:aetheria.runtime")); } [Test] public void AetheriaClientSettingsDocumentsDoNotRequireDaemonFrame() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-client-settings-doc-tests", Path.GetRandomFileName(), "state.cc"); using var client = AetheriaClient .OpenAsync(statePath, "settings-test", pullOnOpen: true) .GetAwaiter() .GetResult(); var player = client.Aetheria().Settings.Player.LatestAsync().GetAwaiter().GetResult(); var verseHost = client.Aetheria().Settings.VerseHost.LatestAsync().GetAwaiter().GetResult(); var catalog = client.Aetheria().Catalog.LatestAsync().GetAwaiter().GetResult(); Assert.AreEqual(AetheriaRuntimeCatalogSnapshot.SchemaId, client.State.Catalog.Sources.Last().SchemaId); Assert.IsNotNull(catalog); Assert.AreEqual(AetheriaRuntimePlayerSettingsDocument.SchemaId, player.Schema); Assert.AreEqual(AetheriaRuntimeVerseHostSettingsDocument.SchemaId, verseHost.Schema); Assert.AreEqual("", player.PlayerName); Assert.AreEqual("", verseHost.VerseId); Assert.AreSame(client.State.Settings.Player, client.Document()); Assert.AreSame(client.State.Settings.VerseHost, client.Document()); } [Test] public void AetheriaRuntimeVerseClientExposesDomainStateFacade() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-verse-domain-state-facade-tests", Path.GetRandomFileName(), "state.cc"); var frame = AetheriaRuntimeDaemonFrameDocument.Create( RunWithTwoEntities(), "daemon", "session-state", 8, 1.5, 0.02); PublishLatestFrameThroughVerseClient(statePath, frame); using var verse = AetheriaRuntimeVerseClient .OpenAsync(statePath, "tool-test", pullOnOpen: true) .GetAwaiter() .GetResult(); var aetheria = verse.Aetheria(); var currentEntity = aetheria.Current.Entity.LatestAsync().GetAwaiter().GetResult(); var latestFrameDocument = verse.Document( AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest); using var latestFrameReactive = latestFrameDocument.Reactive(); Assert.AreEqual("aetheria.current.entity", aetheria.Current.Entity.DocumentId); Assert.AreEqual("zone.0.entity.0", currentEntity.EntityKey); Assert.AreEqual("Player", currentEntity.Entity?.DisplayName); Assert.AreEqual(AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest.ToString(), latestFrameDocument.DocumentId); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Frame, latestFrameReactive.Current.Schema); Assert.AreEqual(8, latestFrameReactive.Current.FrameId); Assert.IsTrue(latestFrameDocument.CanSet); Assert.IsTrue(aetheria.Current.Entity.Sources.Any(source => source.SourceId == AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest.ToString())); } [Test] public void TickRunnerAppliesObservedCommandsAndPublishesFrame() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-tick-runner-tests", Path.GetRandomFileName(), "state.cc"); var run = RunWithTwoEntities(); var targetCommand = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetTarget, "codex", "session-tick", 40, "zone.0.entity.0"); targetCommand.TargetEntityKey = "zone.0.entity.1"; var movementCommand = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetMoveVector, "codex", "session-tick", 41, "zone.0.entity.0"); movementCommand.DirectionX = 1.0; movementCommand.DirectionY = 0.0; movementCommand.ScalarValue = 1.0; var result = AetheriaRuntimeDaemonTickRunner.Tick( statePath, run, new AetheriaRuntimeDaemonTickOptions { DaemonId = "test-daemon", SessionId = "session-tick", VerseId = "aetheria.test", CultMeshAddress = "cultmesh://aetheria.test/eve/providers/aetheria.daemon", FrameId = 42, SimulationTimeSeconds = 12.5, FixedDeltaSeconds = 0.02, ObservedCommands = new[] { targetCommand, movementCommand } }); Assert.AreEqual(2, result.OperationResult.AppliedCommandIds.Count); Assert.AreEqual(0, result.OperationResult.RejectedCommandIds.Count); Assert.AreEqual(1, run.Zones[0].Entities[0].TargetEntityIndex); Assert.AreEqual("zone.0.entity.0", result.Intents.Movement.ActorEntityKey); Assert.AreEqual(1.0, result.Intents.Movement.DirectionX, 0.0001); Assert.AreEqual(12.5, result.Run.Zones[0].SimulationTimeSeconds, 0.0001); Assert.IsTrue(AetheriaRuntimeDaemonFrameStore.TryReadFrame(statePath, out var frame)); Assert.AreEqual(result.FramePath, AetheriaRuntimeDaemonFrameStore.GetFramePath(statePath)); Assert.AreEqual("test-daemon", frame.DaemonId); Assert.AreEqual("session-tick", frame.SessionId); Assert.AreEqual(42, frame.FrameId); Assert.IsTrue(frame.IsAuthoritative); Assert.AreEqual("daemon", frame.StateSource); CollectionAssert.Contains(frame.Capabilities, "aetheria.daemon.intent_state.v1"); CollectionAssert.Contains(frame.Capabilities, AetheriaRuntimeDaemonSchemas.ProviderAdvertisement); CollectionAssert.Contains(frame.Capabilities, AetheriaRuntimeDaemonSchemas.CommandBoundary); CollectionAssert.Contains(frame.Capabilities, AetheriaRuntimeDaemonSchemas.Health); CollectionAssert.Contains(frame.Capabilities, AetheriaRuntimeDaemonSchemas.GameSurface); CollectionAssert.Contains(frame.Capabilities, AetheriaRuntimeDaemonSchemas.EditorSurface); CollectionAssert.AreEquivalent(result.OperationResult.AppliedCommandIds, frame.AppliedCommandIds); CollectionAssert.Contains(frame.AccountedCommandIds, targetCommand.CommandId); CollectionAssert.Contains(frame.AccountedCommandIds, movementCommand.CommandId); Assert.AreEqual(1, frame.Run.Zones[0].Entities[0].TargetEntityIndex); Assert.AreEqual(12.5, frame.Run.Zones[0].SimulationTimeSeconds, 0.0001); Assert.AreEqual( AetheriaRuntimeDaemonPublicationStore.GetProviderAdvertisementPath(statePath), result.ProviderAdvertisementPath); Assert.AreEqual(AetheriaRuntimeDaemonPublicationStore.GetHealthPath(statePath), result.HealthPath); Assert.AreEqual( AetheriaRuntimeDaemonPublicationStore.GetCommandBoundaryPath(statePath), result.CommandBoundaryPath); Assert.AreEqual(AetheriaRuntimeDaemonPublicationStore.GetGameSurfacePath(statePath), result.GameSurfacePath); Assert.AreEqual(AetheriaRuntimeDaemonPublicationStore.GetGameTuiSurfacePath(statePath), result.GameTuiSurfacePath); Assert.AreEqual(AetheriaRuntimeDaemonPublicationStore.GetEditorSurfacePath(statePath), result.EditorSurfacePath); Assert.AreEqual(AetheriaRuntimeDaemonPublicationStore.GetEditorTuiSurfacePath(statePath), result.EditorTuiSurfacePath); Assert.IsTrue(AetheriaRuntimeDaemonPublicationStore.TryReadProviderAdvertisement( statePath, out var providerAdvertisement)); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ProviderAdvertisement, providerAdvertisement.Schema); Assert.AreEqual("aetheria.test", providerAdvertisement.VerseId); Assert.AreEqual("aetheria.daemon", providerAdvertisement.ProviderId); Assert.AreEqual("test-daemon", providerAdvertisement.DaemonId); Assert.AreEqual("cultmesh://aetheria.test/eve/providers/aetheria.daemon", providerAdvertisement.CultMeshAddress); Assert.AreEqual(AetheriaRuntimeDaemonFrameStore.GetFramePath(statePath), providerAdvertisement.FrameWitnessPath); Assert.AreEqual(AetheriaRuntimeDaemonPublicationStore.GetHealthPath(statePath), providerAdvertisement.HealthWitnessPath); Assert.AreEqual( AetheriaRuntimeDaemonPublicationStore.GetCommandBoundaryPath(statePath), providerAdvertisement.CommandBoundaryWitnessPath); Assert.AreEqual( AetheriaRuntimeDaemonPublicationStore.GetGameSurfacePath(statePath), providerAdvertisement.EveGuiSurfaceWitnessPath); Assert.AreEqual( AetheriaRuntimeDaemonPublicationStore.GetGameTuiSurfacePath(statePath), providerAdvertisement.EveTuiSurfaceWitnessPath); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, providerAdvertisement.EveGuiSurfaceId); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, providerAdvertisement.EveTuiSurfaceId); Assert.AreEqual( AetheriaRuntimeDaemonPublicationStore.GetEditorSurfacePath(statePath), providerAdvertisement.EditorGuiSurfaceWitnessPath); Assert.AreEqual( AetheriaRuntimeDaemonPublicationStore.GetEditorTuiSurfacePath(statePath), providerAdvertisement.EditorTuiSurfaceWitnessPath); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, providerAdvertisement.EditorGuiSurfaceId); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, providerAdvertisement.EditorTuiSurfaceId); CollectionAssert.Contains(providerAdvertisement.PublishedSchemas, AetheriaRuntimeDaemonSchemas.Command); CollectionAssert.Contains(providerAdvertisement.PublishedSchemas, AetheriaRuntimeDaemonSchemas.CommandBoundary); CollectionAssert.Contains(providerAdvertisement.PublishedSchemas, AetheriaRuntimeDaemonSchemas.GameSurface); CollectionAssert.Contains(providerAdvertisement.PublishedSchemas, AetheriaRuntimeDaemonSchemas.EditorSurface); Assert.IsTrue(AetheriaRuntimeDaemonPublicationStore.TryReadHealth(statePath, out var health)); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Health, health.Schema); Assert.AreEqual("test-daemon", health.DaemonId); Assert.AreEqual("aetheria.test", health.VerseId); Assert.AreEqual(42, health.FrameId); Assert.AreEqual(2, health.ObservedCommandCount); Assert.AreEqual(2, health.AppliedCommandCount); Assert.AreEqual(0, health.RejectedCommandCount); Assert.AreEqual("daemon-published", health.PublicationSource); Assert.AreEqual("cultcache-witness", health.Transport); Assert.IsTrue(AetheriaRuntimeDaemonPublicationStore.TryReadCommandBoundary( statePath, out var commandBoundary)); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.CommandBoundary, commandBoundary.Schema); Assert.AreEqual("aetheria.daemon.commands", commandBoundary.BoundaryId); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Command, commandBoundary.CommandSchema); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Frame, commandBoundary.ReceiptSchema); Assert.IsTrue(commandBoundary.Commands.Any(entry => entry.Kind == AetheriaRuntimeDaemonCommandKinds.SetMoveVector)); Assert.IsTrue(commandBoundary.Commands.Any(entry => entry.Kind == AetheriaRuntimeDaemonCommandKinds.TransferCargoItem && entry.CommandBody == nameof(AetheriaRuntimeCargoTransferCommand))); Assert.IsTrue(AetheriaRuntimeDaemonPublicationStore.TryReadGameSurface(statePath, out var gameSurface)); Assert.AreEqual("aetheria.daemon", gameSurface.ProviderId); Assert.AreEqual("game.daemon", gameSurface.ProviderKind); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, gameSurface.Surface.Id); Assert.AreEqual(42, gameSurface.Version); Assert.IsTrue(gameSurface.Commands.Any(command => command.Command == "aetheria.daemon.commands.SetMoveVector" && command.Transport == "cultmesh")); Assert.IsTrue(ContainsSurfaceMetric(gameSurface.Surface.Root, "Name", "Player")); Assert.IsTrue(ContainsSurfaceMetric(gameSurface.Surface.Root, "Target", "Target")); Assert.IsTrue(ContainsSurfaceProp( gameSurface.Surface.Root, AetheriaRuntimeSurfaceStateRefs.Source, AetheriaRuntimeDaemonStateRefs.CurrentEntityName)); Assert.IsTrue(ContainsSurfaceStateBinding( gameSurface.Surface.Root, "value", AetheriaRuntimeDaemonStateRefs.CurrentEntityName, AetheriaRuntimeDaemonSchemas.Frame)); Assert.IsTrue(AetheriaRuntimeStateReader.TryResolveDaemonStateRef( frame, health, commandBoundary, AetheriaRuntimeDaemonStateRefs.CurrentEntityName, out var resolvedEntityName)); Assert.AreEqual("Player", resolvedEntityName); Assert.AreEqual( "Target", AetheriaRuntimeStateReader.ResolveEveSurfaceStateRef( statePath, AetheriaRuntimeDaemonStateRefs.CurrentTargetName)); Assert.IsTrue(AetheriaRuntimeDaemonPublicationStore.TryReadGameTuiSurface(statePath, out var gameTuiSurface)); Assert.AreEqual("aetheria.daemon", gameTuiSurface.ProviderId); Assert.AreEqual("game.daemon", gameTuiSurface.ProviderKind); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, gameTuiSurface.Surface.Id); Assert.AreEqual(42, gameTuiSurface.Version); Assert.IsTrue(AetheriaRuntimeDaemonPublicationStore.TryReadEditorSurface(statePath, out var editorSurface)); Assert.AreEqual("aetheria.daemon", editorSurface.ProviderId); Assert.AreEqual("editor.daemon", editorSurface.ProviderKind); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, editorSurface.Surface.Id); Assert.AreEqual(42, editorSurface.Version); Assert.IsTrue(ContainsSurfaceMetric(editorSurface.Surface.Root, "Verse", "aetheria.test")); Assert.IsTrue(ContainsSurfaceMetric(editorSurface.Surface.Root, "Status", "healthy")); Assert.IsTrue(ContainsSurfaceProp( editorSurface.Surface.Root, "surfaceId", AetheriaRuntimeStatRecipeCommands.SurfaceId)); Assert.IsTrue(editorSurface.Commands.Any(command => command.Command == "aetheria.daemon.commands.SensorPing" && command.Transport == "cultmesh")); Assert.IsFalse(editorSurface.Commands.Any(command => command.Command == "aetheria.daemon.commands.TransferCargoItem")); Assert.IsTrue(AetheriaRuntimeDaemonPublicationStore.TryReadEditorTuiSurface(statePath, out var editorTuiSurface)); Assert.AreEqual("aetheria.daemon", editorTuiSurface.ProviderId); Assert.AreEqual("editor.daemon", editorTuiSurface.ProviderKind); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, editorTuiSurface.Surface.Id); Assert.AreEqual(42, editorTuiSurface.Version); Assert.IsTrue(AetheriaRuntimeStateReader.TryReadDaemonGameSurface( statePath, out var unityGameSurface)); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, unityGameSurface.Surface.Id); Assert.AreEqual("aetheria.daemon", unityGameSurface.ProviderId); Assert.IsTrue(unityGameSurface.Commands.Any(command => command.Command == "aetheria.daemon.commands.SetMoveVector" && command.Transport == "cultmesh")); Assert.IsTrue(AetheriaRuntimeStateReader.TryReadDaemonGameTuiSurface( statePath, out var unityGameTuiSurface)); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, unityGameTuiSurface.Surface.Id); Assert.AreEqual("game.daemon", unityGameTuiSurface.ProviderKind); Assert.IsTrue(AetheriaRuntimeStateReader.TryReadDaemonEditorSurface( statePath, out var unityEditorSurface)); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, unityEditorSurface.Surface.Id); Assert.AreEqual("editor.daemon", unityEditorSurface.ProviderKind); Assert.IsTrue(unityEditorSurface.Commands.Any(command => command.Command == "aetheria.daemon.commands.SensorPing" && command.Transport == "cultmesh")); Assert.IsFalse(unityEditorSurface.Commands.Any(command => command.Command == "aetheria.daemon.commands.TransferCargoItem")); Assert.IsTrue(AetheriaRuntimeStateReader.TryReadDaemonEditorTuiSurface( statePath, out var unityEditorTuiSurface)); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, unityEditorTuiSurface.Surface.Id); Assert.AreEqual("editor.daemon", unityEditorTuiSurface.ProviderKind); var genericGameSurface = AetheriaRuntimeStateReader.ReadEveSurface( statePath, AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId); Assert.IsNotNull(genericGameSurface); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, genericGameSurface.Surface.Id); Assert.AreEqual(unityGameSurface.ProviderId, genericGameSurface.ProviderId); Assert.IsTrue(ContainsEveSurfaceMetric(genericGameSurface.Surface.Root, "Target", "Target")); Assert.IsTrue(ContainsEveSurfaceProp( genericGameSurface.Surface.Root, AetheriaRuntimeSurfaceStateRefs.Source, AetheriaRuntimeDaemonStateRefs.CurrentTargetName)); Assert.IsTrue(ContainsEveSurfaceProp( genericGameSurface.Surface.Root, AetheriaRuntimeSurfaceStateBindings.PropPrefix + "value" + AetheriaRuntimeSurfaceStateBindings.SourceIdSuffix, AetheriaRuntimeDaemonStateRefs.CurrentTargetName)); Assert.IsTrue(ContainsEveSurfaceProp( genericGameSurface.Surface.Root, AetheriaRuntimeSurfaceStateBindings.PropPrefix + "value" + AetheriaRuntimeSurfaceStateBindings.SchemaIdSuffix, AetheriaRuntimeDaemonSchemas.Frame)); Assert.IsTrue(ContainsEveSurfaceStateBinding( genericGameSurface.Surface.Root, "value", AetheriaRuntimeDaemonStateRefs.CurrentTargetName, AetheriaRuntimeDaemonSchemas.Frame)); var genericGameTuiSurface = AetheriaRuntimeStateReader.ReadEveSurface( statePath, AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId); Assert.IsNotNull(genericGameTuiSurface); Assert.AreEqual(AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, genericGameTuiSurface.Surface.Id); var genericEditorTuiSurface = AetheriaRuntimeStateReader.ReadEveSurface( statePath, AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId); Assert.IsNotNull(genericEditorTuiSurface); Assert.AreEqual(AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, genericEditorTuiSurface.Surface.Id); } [Test] public void EveSurfaceAdapterResolvesDaemonStateRefsBeforeLowering() { var surface = new EveSurfaceDocument( "surface-state", "gamecult.eve.surface.v1", "aetheria.daemon", "daemon", "Daemon", 1, "", new EveSurfaceTree( "aetheria.test.surface", new EveSurfaceComponent( "aetheria.test.metric", "metric", new Dictionary(StringComparer.Ordinal) { ["label"] = "Target", ["value"] = "stale", [AetheriaRuntimeSurfaceStateRefs.Source] = AetheriaRuntimeDaemonStateRefs.CurrentTargetName }, Array.Empty()), Array.Empty()), Array.Empty()); var resolved = AetheriaRuntimeEveSurfaceAdapter.ResolveStateRefs( surface, stateRef => stateRef == AetheriaRuntimeDaemonStateRefs.CurrentTargetName ? "Live Target" : ""); Assert.IsTrue(ContainsEveSurfaceMetric(resolved.Surface.Root, "Target", "Live Target")); Assert.IsTrue(ContainsEveSurfaceProp( resolved.Surface.Root, AetheriaRuntimeSurfaceStateRefs.Source, AetheriaRuntimeDaemonStateRefs.CurrentTargetName)); } [Test] public void EveSurfaceAdapterResolvesTypedPointerPropsBeforeLowering() { var surface = new EveSurfaceDocument( "surface-state", "gamecult.eve.surface.v1", "aetheria.daemon", "daemon", "Daemon", 1, "", new EveSurfaceTree( "aetheria.test.surface", new EveSurfaceComponent( "aetheria.test.metric", "metric", new Dictionary(StringComparer.Ordinal) { ["label"] = "Heat", ["description"] = "stale", ["descriptionRef"] = AetheriaRuntimeDaemonStateRefs.CurrentTargetName, [AetheriaRuntimeSurfaceStateRefs.Value] = AetheriaRuntimeDaemonStateRefs.CurrentTargetName }, Array.Empty()), Array.Empty()), Array.Empty()); var resolved = AetheriaRuntimeEveSurfaceAdapter.ResolveStateRefs( surface, stateRef => stateRef == AetheriaRuntimeDaemonStateRefs.CurrentTargetName ? "Live Target" : ""); Assert.IsTrue(ContainsEveSurfaceProp(resolved.Surface.Root, "description", "Live Target")); Assert.IsTrue(ContainsEveSurfaceProp(resolved.Surface.Root, "descriptionRef", AetheriaRuntimeDaemonStateRefs.CurrentTargetName)); Assert.IsTrue(ContainsEveSurfaceProp(resolved.Surface.Root, "value", "Live Target")); Assert.IsTrue(ContainsEveSurfaceProp(resolved.Surface.Root, AetheriaRuntimeSurfaceStateRefs.Value, AetheriaRuntimeDaemonStateRefs.CurrentTargetName)); } [Test] public void RuntimeStateReaderResolvesItemStatRefsFromDaemonFrame() { var frame = new AetheriaRuntimeDaemonFrameDocument { Run = new AetheriaRuntimeRunCheckpointCommit { Zones = new[] { new AetheriaRuntimeZoneSnapshotCommit { Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { Equipment = new[] { new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "test-laser", Quality = 0.5, Durability = 1.0, Enabled = true, Temperature = 0.5 } } } } } } } } }; var statValue = new AetheriaRuntimeBehaviorValue( "performance-stat", "", 0, false, "", "", new[] { NumberValue(10), NumberValue(20), NumberValue(1), NumberValue(0), NumberValue(1), EmptyBehaviorValue("stat-recipe") }, Array.Empty()); var catalog = new AetheriaRuntimeCatalogSnapshot( new[] { CatalogItem( "test-laser", new[] { new AetheriaRuntimeBehaviorPayload( 0, "Weapon", 2, new[] { new AetheriaRuntimeBehaviorField(7, statValue) }) }) }, Array.Empty(), Array.Empty()); Assert.IsTrue(AetheriaRuntimeStateReader.TryResolveDaemonItemStatRef( frame, catalog, AetheriaRuntimeDaemonItemStatQueries.ItemStatRef("test-laser", "Weapon", 2, 7), out var value)); Assert.AreEqual("12.5", value); } [Test] public void TickRunnerSkipsPreviouslyAccountedObservedCommands() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-tick-runner-tests", Path.GetRandomFileName(), "state.cc"); var run = RunWithTwoEntities(); var targetCommand = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetTarget, "codex", "session-tick", 40, "zone.0.entity.0"); targetCommand.TargetEntityKey = "zone.0.entity.1"; var result = AetheriaRuntimeDaemonTickRunner.Tick( statePath, run, new AetheriaRuntimeDaemonTickOptions { DaemonId = "test-daemon", SessionId = "session-tick", FrameId = 43, SimulationTimeSeconds = 12.52, FixedDeltaSeconds = 0.02, ObservedCommands = new[] { targetCommand }, AccountedCommandIds = new[] { targetCommand.CommandId } }); Assert.AreEqual(0, result.OperationResult.AppliedCommandIds.Count); Assert.AreEqual(0, result.OperationResult.RejectedCommandIds.Count); Assert.AreEqual(-1, run.Zones[0].Entities[0].TargetEntityIndex); CollectionAssert.Contains(result.Frame.AccountedCommandIds, targetCommand.CommandId); Assert.IsTrue(AetheriaRuntimeDaemonPublicationStore.TryReadHealth(statePath, out var health)); Assert.AreEqual(1, health.ObservedCommandCount); Assert.AreEqual(0, health.AppliedCommandCount); Assert.AreEqual(0, health.RejectedCommandCount); } [Test] public void SoaViewFactoryDescribesDaemonOwnedObserverReadOnlySlabs() { var buffer = new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "hot-transform-0", DisplayName = "Hot Transform Page 0", Backend = AetheriaRuntimeDaemonSoaBackends.MemoryMappedFile, Location = "Local\\AetheriaHotTransform0", ByteLength = 4096, Generation = 77, DaemonWritable = true, ObserverWritable = false }; var position = new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "position", Kind = AetheriaRuntimeDaemonSoaColumnKinds.Position, BufferId = buffer.BufferId, ScalarType = "float3", ByteOffset = 0, ElementStride = 12, ElementCount = 128, Unit = "world_units", CoordinateSpace = "zone" }; var dirtyRange = new AetheriaRuntimeDaemonSoaDirtyRangeDocument { ColumnId = position.ColumnId, StartIndex = 16, Count = 8, Generation = 77 }; var view = AetheriaRuntimeDaemonSoaViewDocument.Create( "ymir-daemon", "session-soa", 42, 77, new[] { buffer }, new[] { position }, new[] { dirtyRange }, AetheriaRuntimeDaemonSoaBackends.MemoryMappedFile, AetheriaRuntimeDaemonSoaSynchronizationModes.DoubleBuffered); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.SoaView, view.Schema); Assert.AreEqual("ymir-daemon", view.DaemonId); Assert.AreEqual("session-soa", view.SessionId); Assert.AreEqual(42, view.FrameId); Assert.AreEqual(77, view.Generation); Assert.IsTrue(view.IsAuthoritative); Assert.AreEqual(AetheriaRuntimeDaemonSoaBackends.MemoryMappedFile, view.Backend); Assert.AreEqual(AetheriaRuntimeDaemonSoaSynchronizationModes.DoubleBuffered, view.SynchronizationMode); Assert.AreEqual(1, view.Buffers.Count); Assert.IsTrue(view.Buffers[0].DaemonWritable); Assert.IsFalse(view.Buffers[0].ObserverWritable); Assert.AreEqual(AetheriaRuntimeDaemonSoaColumnKinds.Position, view.Columns[0].Kind); Assert.AreEqual(16, view.DirtyRanges[0].StartIndex); Assert.AreEqual(8, view.DirtyRanges[0].Count); Assert.IsNotEmpty(view.PublishedAtUtc); } [Test] public void SoaViewIndexBindsReadOnlyDirectMemoryColumns() { var view = AetheriaRuntimeDaemonSoaViewDocument.Create( "ymir-daemon", "session-soa-index", 90, 91, new[] { new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "transform-hot", Backend = AetheriaRuntimeDaemonSoaBackends.MemoryMappedFile, Location = "Local\\AetheriaTransformHot", ByteOffset = 128, ByteLength = 512, Generation = 91, DaemonWritable = true, ObserverWritable = false } }, new[] { new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "position", Kind = AetheriaRuntimeDaemonSoaColumnKinds.Position, BufferId = "transform-hot", ScalarType = "float3", ByteOffset = 16, ElementStride = 12, ElementCount = 64, Unit = "world_units", CoordinateSpace = "zone" } }, new[] { new AetheriaRuntimeDaemonSoaDirtyRangeDocument { ColumnId = "position", StartIndex = 8, Count = 4, Generation = 91 } }, AetheriaRuntimeDaemonSoaBackends.MemoryMappedFile); var index = AetheriaRuntimeDaemonSoaViewIndex.Build(view); Assert.IsTrue(index.IsValid); Assert.IsTrue(index.TryGetFirstColumnOfKind(AetheriaRuntimeDaemonSoaColumnKinds.Position, out var binding)); Assert.AreEqual("position", binding.Column.ColumnId); Assert.AreEqual("transform-hot", binding.Buffer.BufferId); Assert.AreEqual(144, binding.AbsoluteByteOffset); Assert.AreEqual(768, binding.ByteLength); Assert.IsTrue(binding.DirectMemoryCompatible); Assert.AreEqual(1, index.GetDirtyRanges("position").Count); Assert.AreEqual(8, index.GetDirtyRanges("position")[0].StartIndex); } [Test] public void SoaViewIndexBindsDaemonAuthoredRenderGroups() { var view = AetheriaRuntimeDaemonSoaViewDocument.Create( "aetheria-daemon", "session-render-groups", 120, 121, new[] { new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "render-hot", Backend = AetheriaRuntimeDaemonSoaBackends.SharedNativeMemory, ByteLength = 256, Generation = 121, DaemonWritable = true, ObserverWritable = false } }, new[] { new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "render-group-id", Kind = AetheriaRuntimeDaemonSoaColumnKinds.RenderGroupId, BufferId = "render-hot", ScalarType = "uint32", ByteOffset = 0, ElementStride = 4, ElementCount = 64 } }, backend: AetheriaRuntimeDaemonSoaBackends.SharedNativeMemory, renderGroups: new[] { new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 7, MeshKey = "ships/djinni", MaterialKey = "materials/ships/hull", SubMeshIndex = 0, Layer = 12, ShaderKey = "aetheria/daemon-indirect", DisplayName = "Djinni hull", InstanceCount = 24, BoundsCenterX = 10, BoundsCenterY = 20, BoundsCenterZ = 30, BoundsSizeX = 100, BoundsSizeY = 80, BoundsSizeZ = 60, ShadowMode = AetheriaRuntimeDaemonRenderShadowModes.TwoSided, ReceiveShadows = false, DefaultScale = 2.5f, Lod = 2 } }); var index = AetheriaRuntimeDaemonSoaViewIndex.Build(view); Assert.IsTrue(index.IsValid); Assert.IsTrue(index.TryGetFirstColumnOfKind(AetheriaRuntimeDaemonSoaColumnKinds.RenderGroupId, out var groupColumn)); Assert.AreEqual("render-group-id", groupColumn.Column.ColumnId); Assert.IsTrue(groupColumn.DirectMemoryCompatible); Assert.AreEqual(1, index.RenderGroups.Count); Assert.IsTrue(index.TryGetRenderGroup(7, out var renderGroup)); Assert.AreEqual("ships/djinni", renderGroup.MeshKey); Assert.AreEqual("materials/ships/hull", renderGroup.MaterialKey); Assert.AreEqual(12, renderGroup.Layer); Assert.AreEqual(24, renderGroup.InstanceCount); Assert.AreEqual(10, renderGroup.BoundsCenterX); Assert.AreEqual(100, renderGroup.BoundsSizeX); Assert.AreEqual(AetheriaRuntimeDaemonRenderShadowModes.TwoSided, renderGroup.ShadowMode); Assert.IsFalse(renderGroup.ReceiveShadows); Assert.AreEqual(2.5f, renderGroup.DefaultScale); Assert.AreEqual(2, renderGroup.Lod); } [Test] public void DaemonRenderQueriesFilterRenderGroupsByBounds() { var view = AetheriaRuntimeDaemonSoaViewDocument.Create( "aetheria-daemon", "session-render-query", 130, 131, new[] { new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "render-hot", ByteLength = 128 } }, new[] { new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "render-group-id", Kind = AetheriaRuntimeDaemonSoaColumnKinds.RenderGroupId, BufferId = "render-hot", ScalarType = "uint32", ElementStride = 4, ElementCount = 16 } }, renderGroups: new[] { new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 1, MeshKey = "ships/djinni", MaterialKey = "materials/ships/hull", BoundsCenterX = 0, BoundsCenterY = 0, BoundsCenterZ = 0, BoundsSizeX = 8, BoundsSizeY = 8, BoundsSizeZ = 8 }, new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 2, MeshKey = "ships/far", MaterialKey = "materials/ships/hull", BoundsCenterX = 100, BoundsCenterY = 0, BoundsCenterZ = 0, BoundsSizeX = 8, BoundsSizeY = 8, BoundsSizeZ = 8 } }); var index = AetheriaRuntimeDaemonSoaViewIndex.Build(view); var groups = new List(); var count = AetheriaRuntimeDaemonRenderQueries.QueryRenderGroups( index, -10, -10, -10, 10, 10, 10, groups); Assert.AreEqual(1, count); Assert.AreEqual(1, groups.Count); Assert.AreEqual(1, groups[0].GroupId); } [Test] public void DaemonRenderQueriesFilterGravityInfluencesByXzViewport() { var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0, GravityTerrainRadius = 100, GravityTerrainDepth = 2, GravityTerrainDepthExponent = 1, GravityTerrainWaveFrequency = 1, Bodies = new[] { new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:near", OrbitKey = "orbit:near", Kind = "gas_giant", GravityInfluenceCenterX = 4, GravityInfluenceCenterZ = 0, GravityInfluenceRadius = 6, GravityWellDepth = 20, GravityDepthExponent = 12, GravityWaveRadius = 9, GravityWaveDepth = 3, GravityWaveSpeed = 2 }, new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:far", OrbitKey = "orbit:far", Kind = "planet", GravityInfluenceCenterX = 100, GravityInfluenceCenterZ = 0, GravityInfluenceRadius = 4, GravityWellDepth = 10 }, new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:legacy-missing-radius", OrbitKey = "orbit:legacy", Kind = "planet", GravityInfluenceCenterX = 0, GravityInfluenceCenterZ = 0 } } }; var brushes = new List(); var count = AetheriaRuntimeDaemonRenderQueries.QueryGravityInfluences( zone, new rect(-10, -10, 10, 10), brushes); Assert.AreEqual(1, count); Assert.AreEqual("body:near", brushes[0].BodyKey); Assert.AreEqual(AetheriaRuntimeGravityInfluenceKind.GasGiant, brushes[0].Kind); Assert.AreEqual(9, brushes[0].Radius); Assert.AreEqual(20, brushes[0].GravityDepth); Assert.AreEqual(12, brushes[0].GravityDepthExponent); Assert.AreEqual(9, brushes[0].WaveRadius); Assert.AreEqual(3, brushes[0].WaveDepth); Assert.AreEqual(2, brushes[0].WaveSpeed); var height = AetheriaRuntimeDaemonRenderQueries.EvaluateGravityTerrainHeight(zone, 4, 0, 0); Assert.AreEqual(-24.9968, height, 0.0001); } [Test] public void DaemonRenderQueriesResolveZoneRenderRadiusFromDaemonTerrain() { var zone = new AetheriaRuntimeZoneSnapshotCommit { GravityTerrainRadius = 128 }; Assert.AreEqual(128, AetheriaRuntimeDaemonRenderQueries.ResolveZoneRenderRadius(zone, 2000)); Assert.AreEqual(2000, AetheriaRuntimeDaemonRenderQueries.ResolveZoneRenderRadius(null, 2000)); Assert.AreEqual(0, AetheriaRuntimeDaemonRenderQueries.ResolveZoneRenderRadius(null, -5)); } [Test] public void DaemonRenderQueriesPublishGravityTerrainMaterialBand() { var zone = new AetheriaRuntimeZoneSnapshotCommit { GravityTerrainDepth = 20, GravityTerrainDepthExponent = 2 }; var band = AetheriaRuntimeDaemonRenderQueries.QueryGravityTerrainBand(zone, 0.25, 3); Assert.AreEqual(11.25, band.StartDepth, 0.0001); Assert.AreEqual(11.75, band.DepthRange, 0.0001); } [Test] public void ZoneDetailsProjectionReadsMassRadiusAndContentsFromDaemonZone() { var zone = new AetheriaRuntimeZoneSnapshotCommit { Name = "Tir Na Nog", GravityTerrainRadius = 420, Bodies = new[] { new AetheriaRuntimeBodySnapshotCommit { Kind = "planet", Mass = 10 }, new AetheriaRuntimeBodySnapshotCommit { Kind = "gas_giant", Mass = 30 }, new AetheriaRuntimeBodySnapshotCommit { Kind = "asteroid_belt" } }, Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { HullItemKey = "station-hull" }, new AetheriaRuntimeEntitySnapshotCommit { HullItemKey = "ship-hull" } } }; var projection = AetheriaRuntimeZoneDetailsSurfaceBuilder.ProjectDaemonZone( zone, key => key == "station-hull" ? "Station" : "Ship"); var state = AetheriaRuntimeZoneDetailsSurfaceBuilder.Project( zone.Name, "GameCult", projection.Mass.ToString("0"), projection.Radius.ToString("0"), new[] { "A", "B" }, projection.Bodies, projection.Entities, projection.HasContents, ""); Assert.AreEqual(40, projection.Mass, 0.0001); Assert.AreEqual(420, projection.Radius, 0.0001); Assert.IsTrue(projection.HasContents); Assert.AreEqual("1", state.Planets); Assert.AreEqual("1", state.GasGiants); Assert.AreEqual("1", state.AsteroidBelts); Assert.AreEqual("1", state.Stations); Assert.AreEqual("1", state.Ships); } [Test] public void DaemonRenderQueriesPublishBodyPosesFromZoneSnapshot() { var zone = new AetheriaRuntimeZoneSnapshotCommit { Orbits = new[] { new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:parent", FixedPositionX = 10, FixedPositionY = 20 }, new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:child", ParentOrbitKey = "orbit:parent", Distance = 5, Phase = 0.25 } }, Bodies = new[] { new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:child", OrbitKey = "orbit:child", Kind = "planet" }, new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:explicit", OrbitKey = "orbit:missing", Kind = "gas_giant", GravityInfluenceCenterX = -3, GravityInfluenceCenterZ = 7, GravityWaveSpeed = 3.5 } } }; var poses = AetheriaRuntimeDaemonRenderQueries.QueryBodyPoses(zone); Assert.AreEqual(2, poses.Length); Assert.AreEqual("body:child", poses[0].BodyKey); Assert.AreEqual("orbit:parent", poses[0].ParentOrbitKey); Assert.AreEqual(10, poses[0].CenterX, 0.0001); Assert.AreEqual(25, poses[0].CenterZ, 0.0001); Assert.AreEqual(10, poses[0].ParentCenterX, 0.0001); Assert.AreEqual(20, poses[0].ParentCenterZ, 0.0001); Assert.AreEqual("body:explicit", poses[1].BodyKey); Assert.AreEqual(-3, poses[1].CenterX, 0.0001); Assert.AreEqual(7, poses[1].CenterZ, 0.0001); Assert.AreEqual(3.5, poses[1].GravityWaveSpeed, 0.0001); } [Test] public void DaemonRenderQueriesPublishBodyViewsFromZoneSnapshot() { var zone = new AetheriaRuntimeZoneSnapshotCommit { Orbits = new[] { new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:planet", FixedPositionX = 12, FixedPositionY = -8 }, new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:belt", Distance = 30 } }, Bodies = new[] { new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:planet", OrbitKey = "orbit:planet", Kind = "planet", GravityInfluenceRadius = 40, GravityWellDepth = 7 }, new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:belt", OrbitKey = "orbit:belt", Kind = "asteroid_belt" } } }; var views = new List(); var count = AetheriaRuntimeDaemonRenderQueries.QueryBodyViews(zone, views); Assert.AreEqual(2, count); Assert.AreEqual("body:planet", views[0].Body.BodyKey); Assert.IsFalse(views[0].IsAsteroidBelt); Assert.AreEqual(12, views[0].Pose.CenterX, 0.0001); Assert.AreEqual(-8, views[0].Pose.CenterZ, 0.0001); Assert.AreEqual(40, views[0].Body.GravityInfluenceRadius, 0.0001); Assert.AreEqual(7, views[0].Body.GravityWellDepth, 0.0001); Assert.AreEqual("body:belt", views[1].Body.BodyKey); Assert.IsTrue(views[1].IsAsteroidBelt); count = AetheriaRuntimeDaemonRenderQueries.QueryBodyViews( zone, new rect(0, -20, 30, 10), views); Assert.AreEqual(1, count); Assert.AreEqual("body:planet", views[0].Body.BodyKey); } [Test] public void DaemonRenderQueriesPublishAsteroidBeltPosesFromZoneSnapshot() { var zone = new AetheriaRuntimeZoneSnapshotCommit { Orbits = new[] { new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:parent", FixedPositionX = 11, FixedPositionY = -4 }, new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:belt", ParentOrbitKey = "orbit:parent", Distance = 30 } }, Bodies = new[] { new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:belt", OrbitKey = "orbit:belt", Kind = "asteroid_belt", Asteroids = new[] { new AetheriaRuntimeAsteroidCommit { Distance = 3 }, new AetheriaRuntimeAsteroidCommit { Distance = 7 }, new AetheriaRuntimeAsteroidCommit { Distance = 5 } } }, new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:planet", OrbitKey = "orbit:belt", Kind = "planet" } } }; var poses = AetheriaRuntimeDaemonRenderQueries.QueryAsteroidBeltPoses(zone); Assert.AreEqual(1, poses.Length); Assert.AreEqual("body:belt", poses[0].BodyKey); Assert.AreEqual("orbit:belt", poses[0].OrbitKey); Assert.AreEqual(11, poses[0].CenterX, 0.0001); Assert.AreEqual(-4, poses[0].CenterZ, 0.0001); Assert.AreEqual(7, poses[0].Radius, 0.0001); Assert.AreEqual(3, poses[0].AsteroidCount); } [Test] public void DaemonRenderQueriesPublishAsteroidInstancePosesForVisibleBelt() { var zone = new AetheriaRuntimeZoneSnapshotCommit { Orbits = new[] { new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:parent", FixedPositionX = 10, FixedPositionY = 20 }, new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:belt", ParentOrbitKey = "orbit:parent", Distance = 100 } }, Bodies = new[] { new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:belt", OrbitKey = "orbit:belt", Kind = "asteroid_belt", Asteroids = new[] { new AetheriaRuntimeAsteroidCommit { Distance = 5, Phase = 0, Size = 2, RotationSpeed = 3 }, new AetheriaRuntimeAsteroidCommit { Distance = 7, Phase = 0.25, Size = 4, Damage = 1, RotationSpeed = 2 }, new AetheriaRuntimeAsteroidCommit { Distance = 11, Phase = 0.5, Size = 9, RespawnTimer = 12 } } }, new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:other", OrbitKey = "orbit:belt", Kind = "asteroid_belt", Asteroids = new[] { new AetheriaRuntimeAsteroidCommit { Distance = 99, Size = 99 } } } } }; var poses = AetheriaRuntimeDaemonRenderQueries.QueryAsteroidInstancePoses(zone, "body:belt", 4); Assert.AreEqual(3, poses.Length); Assert.AreEqual("body:belt", poses[0].BodyKey); Assert.AreEqual(0, poses[0].AsteroidIndex); Assert.AreEqual(15, poses[0].PositionX, 0.0001); Assert.AreEqual(20, poses[0].PositionZ, 0.0001); Assert.AreEqual(12, poses[0].Rotation, 0.0001); Assert.AreEqual(2, poses[0].Size, 0.0001); Assert.AreEqual(10, poses[1].PositionX, 0.0001); Assert.AreEqual(27, poses[1].PositionZ, 0.0001); Assert.AreEqual(3, poses[1].Size, 0.0001); Assert.AreEqual(0, poses[2].Size, 0.0001); } [Test] public void DaemonRenderQueriesPublishCompassMarkersFromVisibleContacts() { var zone = new AetheriaRuntimeZoneSnapshotCommit { Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 0, PositionX = 10, PositionZ = 20, Contacts = new[] { new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 1, InfoGathered = 0.8, Visible = true, Hostile = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 2, InfoGathered = 0.2, Visible = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 3, InfoGathered = 0.9, Visible = false }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 4, InfoGathered = 0.9, Visible = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 99, InfoGathered = 0.9, Visible = true } } }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 1, PositionX = 13, PositionZ = 24 }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 2, PositionX = 100, PositionZ = 20 }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 3, PositionX = 10, PositionZ = 200 }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 4, PositionX = 11, PositionZ = 20 } } }; var markers = new List(); var count = AetheriaRuntimeDaemonRenderQueries.QueryCompassMarkers( zone, 0, 0.5, 2, markers); Assert.AreEqual(1, count); Assert.AreEqual(1, markers.Count); Assert.AreEqual(1, markers[0].TargetEntityIndex); Assert.AreEqual(13, markers[0].PositionX, 0.0001); Assert.AreEqual(24, markers[0].PositionZ, 0.0001); Assert.AreEqual(3, markers[0].DeltaX, 0.0001); Assert.AreEqual(4, markers[0].DeltaZ, 0.0001); Assert.AreEqual(5, markers[0].Distance, 0.0001); Assert.AreEqual(0.8, markers[0].InfoGathered, 0.0001); Assert.IsTrue(markers[0].Hostile); } [Test] public void DaemonRenderQueriesPublishVisibleEntityIndicesFromObserverContacts() { var zone = new AetheriaRuntimeZoneSnapshotCommit { Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 10, Contacts = new[] { new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 11, InfoGathered = 0.7, Visible = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 12, InfoGathered = 0.3, Visible = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 13, InfoGathered = 0.9, Visible = false }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 99, InfoGathered = 0.9, Visible = true } } }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 11 }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 12 }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 13 } } }; var visible = new List(); var count = AetheriaRuntimeDaemonRenderQueries.QueryVisibleEntityIndices( zone, 10, 0.5, visible); Assert.AreEqual(2, count); Assert.AreEqual(10, visible[0]); Assert.AreEqual(11, visible[1]); } [Test] public void DaemonRenderQueriesPublishCollectiveVisibleEntitiesInsideObjectsViewport() { var zone = new AetheriaRuntimeZoneSnapshotCommit { Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 1, PositionX = 0, PositionZ = 0, Contacts = new[] { new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 3, InfoGathered = 0.8, Visible = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 4, InfoGathered = 0.4, Visible = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 6, InfoGathered = 0.9, Visible = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 7, InfoGathered = 0.9, Visible = true } } }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 2, PositionX = 30, PositionZ = 0, Contacts = new[] { new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 5, InfoGathered = 0.9, Visible = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 7, InfoGathered = 0.9, Visible = true } } }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 3, PositionX = 8, PositionZ = 8 }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 4, PositionX = 9, PositionZ = 9 }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 5, PositionX = 12, PositionZ = 0 }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 6, PositionX = 100, PositionZ = 100 }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 7, PositionX = 5, PositionZ = 5 } } }; var visible = new List(); var count = AetheriaRuntimeDaemonRenderQueries.QueryObjectsViewportEntityIndices( zone, new[] { 1, 2 }, 0.5, new rect(-10, -10, 40, 20), visible); Assert.AreEqual(5, count); CollectionAssert.AreEqual(new[] { 1, 2, 3, 5, 7 }, visible); var objects = AetheriaRuntimeDaemonRenderQueries.QueryObjectsViewport( zone, new[] { 1, 2 }, 0.5, new rect(-10, -10, 40, 20)); Assert.AreEqual(5, objects.Length); Assert.AreEqual(1, objects[0].EntityIndex); Assert.IsTrue(objects[0].Controlled); Assert.AreEqual(new double3(0, 0, 0), objects[0].Position); Assert.AreEqual(new double2(0, 0), objects[0].Xy); Assert.AreEqual(7, objects[4].EntityIndex); Assert.IsFalse(objects[4].Controlled); Assert.AreEqual(new double2(5, 5), objects[4].Xy); } [Test] public void DaemonRenderQueriesPublishWormholeExitsFromZoneAdjacency() { var currentZone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0, PositionX = 10, PositionY = 20, AdjacentZoneIndices = new[] { 1, 99 } }; var run = new AetheriaRuntimeRunCheckpointCommit { Zones = new[] { currentZone, new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 1, PositionX = 13, PositionY = 24 } } }; var exits = new List(); var count = AetheriaRuntimeDaemonRenderQueries.QueryWormholeExits( run, currentZone, 100, 0.5, exits); Assert.AreEqual(1, count); Assert.AreEqual(1, exits[0].TargetZoneIndex); Assert.AreEqual(0.6, exits[0].DirectionX, 0.0001); Assert.AreEqual(0.8, exits[0].DirectionZ, 0.0001); Assert.AreEqual(30, exits[0].PositionX, 0.0001); Assert.AreEqual(40, exits[0].PositionZ, 0.0001); } [Test] public void SoaViewIndexRejectsInvalidRenderGroups() { var view = AetheriaRuntimeDaemonSoaViewDocument.Create( "aetheria-daemon", "session-render-groups-invalid", 122, 123, new[] { new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "render-hot", ByteLength = 16 } }, new[] { new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "render-group-id", Kind = AetheriaRuntimeDaemonSoaColumnKinds.RenderGroupId, BufferId = "render-hot", ScalarType = "uint32", ElementStride = 4, ElementCount = 4 } }, renderGroups: new[] { new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 3, MeshKey = "ships/djinni" }, new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 3, MeshKey = "ships/djinni", MaterialKey = "materials/ships/hull" }, new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 4, MeshKey = "ships/pirate", MaterialKey = "materials/ships/hull", SubMeshIndex = -1 }, new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 5, MeshKey = "ships/frigate", MaterialKey = "materials/ships/hull", InstanceCount = -2 }, new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 6, MeshKey = "ships/cruiser", MaterialKey = "materials/ships/hull", BoundsSizeX = 10, BoundsSizeY = 0, BoundsSizeZ = 10 }, new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 7, MeshKey = "ships/hauler", MaterialKey = "materials/ships/hull", ShadowMode = "unity-local-policy" }, new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 8, MeshKey = "ships/shuttle", MaterialKey = "materials/ships/hull", DefaultScale = 0 }, new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 9, MeshKey = "ships/scout", MaterialKey = "materials/ships/hull", Lod = -2 } }); var index = AetheriaRuntimeDaemonSoaViewIndex.Build(view); var errors = string.Join("\n", index.ValidationErrors); Assert.IsFalse(index.IsValid); StringAssert.Contains("missing a material key", errors); StringAssert.Contains("Duplicate render group id '3'", errors); StringAssert.Contains("negative submesh index", errors); StringAssert.Contains("invalid instance count", errors); StringAssert.Contains("must publish positive render bounds", errors); StringAssert.Contains("invalid shadow mode", errors); StringAssert.Contains("non-positive default scale", errors); StringAssert.Contains("invalid render lod", errors); } [Test] public void SoaViewIndexRejectsInvalidRenderSemanticColumnTypes() { var view = AetheriaRuntimeDaemonSoaViewDocument.Create( "aetheria-daemon", "session-render-column-types-invalid", 126, 127, new[] { new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "render-hot", ByteLength = 64 } }, new[] { new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "render-scale", Kind = AetheriaRuntimeDaemonSoaColumnKinds.RenderScale, BufferId = "render-hot", ScalarType = "uint32", ElementStride = 4, ElementCount = 4 }, new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "render-visibility", Kind = AetheriaRuntimeDaemonSoaColumnKinds.RenderVisibility, BufferId = "render-hot", ScalarType = "float32", ByteOffset = 16, ElementStride = 4, ElementCount = 4 }, new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "render-lod", Kind = AetheriaRuntimeDaemonSoaColumnKinds.RenderLod, BufferId = "render-hot", ScalarType = "float32", ByteOffset = 32, ElementStride = 4, ElementCount = 4 }, new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "physics-body-radius", Kind = AetheriaRuntimeDaemonSoaColumnKinds.PhysicsBodyRadius, BufferId = "render-hot", ScalarType = "uint32", ByteOffset = 48, ElementStride = 4, ElementCount = 4 } }); var index = AetheriaRuntimeDaemonSoaViewIndex.Build(view); var errors = string.Join("\n", index.ValidationErrors); Assert.IsFalse(index.IsValid); StringAssert.Contains("render scale must use float32", errors); StringAssert.Contains("render visibility must use bool, byte, or uint8", errors); StringAssert.Contains("render lod must use int32", errors); StringAssert.Contains("physics.body.radius must use float32", errors); } [Test] public void SoaViewIndexRequiresRenderGroupIdColumnForMultipleRenderGroups() { var view = AetheriaRuntimeDaemonSoaViewDocument.Create( "aetheria-daemon", "session-render-groups-without-group-column", 124, 125, Array.Empty(), Array.Empty(), renderGroups: new[] { new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 1, MeshKey = "ships/djinni", MaterialKey = "materials/ships/hull", BoundsSizeX = 10, BoundsSizeY = 10, BoundsSizeZ = 10 }, new AetheriaRuntimeDaemonRenderGroupDocument { GroupId = 2, MeshKey = "ships/frigate", MaterialKey = "materials/ships/hull", BoundsSizeX = 10, BoundsSizeY = 10, BoundsSizeZ = 10 } }); var index = AetheriaRuntimeDaemonSoaViewIndex.Build(view); var errors = string.Join("\n", index.ValidationErrors); Assert.IsFalse(index.IsValid); StringAssert.Contains("Multiple render groups require a render group id column", errors); } [Test] public void SoaViewIndexRejectsObserverWritableAndOutOfBoundsColumns() { var view = AetheriaRuntimeDaemonSoaViewDocument.Create( "ymir-daemon", "session-soa-index-invalid", 92, 93, new[] { new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "mutable-hot", Backend = AetheriaRuntimeDaemonSoaBackends.SharedNativeMemory, ByteLength = 16, ObserverWritable = true } }, new[] { new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "heat", Kind = AetheriaRuntimeDaemonSoaColumnKinds.Heat, BufferId = "mutable-hot", ScalarType = "float32", ByteOffset = 8, ElementStride = 4, ElementCount = 8 } }); var index = AetheriaRuntimeDaemonSoaViewIndex.Build(view); Assert.IsFalse(index.IsValid); Assert.GreaterOrEqual(index.ValidationErrors.Count, 2); Assert.IsTrue(index.TryGetFirstColumnOfKind(AetheriaRuntimeDaemonSoaColumnKinds.Heat, out var binding)); Assert.IsFalse(binding.DirectMemoryCompatible); } [Test] public void SoaViewStorePublishesLatestDaemonView() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-soa-view-store-tests", Path.GetRandomFileName(), "state.cc"); var view = AetheriaRuntimeDaemonSoaViewDocument.Create( "aetheria-daemon", "session-soa-store", 123, 456, new[] { new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "entity-hot-0", Backend = AetheriaRuntimeDaemonSoaBackends.CultCache, Location = "cultcache://aetheria/run/local/entity-hot-0", ByteLength = 8192, Generation = 456, DaemonWritable = true, ObserverWritable = false } }, new[] { new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "heat", Kind = AetheriaRuntimeDaemonSoaColumnKinds.Heat, BufferId = "entity-hot-0", ScalarType = "float32", ByteOffset = 1024, ElementStride = 4, ElementCount = 256, Unit = "thermal_units" } }, new[] { new AetheriaRuntimeDaemonSoaDirtyRangeDocument { ColumnId = "heat", StartIndex = 0, Count = 256, Generation = 456 } }); var viewPath = AetheriaRuntimeDaemonSoaViewStore.PublishView(statePath, view); var read = AetheriaRuntimeDaemonSoaViewStore.TryReadView(statePath, out var stored); Assert.IsTrue(read); Assert.AreEqual(AetheriaRuntimeStateBoundary.GetDaemonSoaViewPath(statePath), viewPath); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.SoaView, stored.Schema); Assert.AreEqual("aetheria-daemon", stored.DaemonId); Assert.AreEqual("session-soa-store", stored.SessionId); Assert.AreEqual(123, stored.FrameId); Assert.AreEqual(456, stored.Generation); Assert.IsTrue(stored.IsAuthoritative); Assert.AreEqual(1, stored.Buffers.Count); Assert.AreEqual("entity-hot-0", stored.Buffers[0].BufferId); Assert.IsFalse(stored.Buffers[0].ObserverWritable); Assert.AreEqual(1, stored.Columns.Count); Assert.AreEqual(AetheriaRuntimeDaemonSoaColumnKinds.Heat, stored.Columns[0].Kind); Assert.AreEqual(1, stored.DirtyRanges.Count); Assert.AreEqual(256, stored.DirtyRanges[0].Count); } [Test] public void SoaFramePublisherPublishesMappableCurrentZoneEntitySlab() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-soa-frame-publisher-tests", Path.GetRandomFileName(), "state.cc"); var frame = AetheriaRuntimeDaemonFrameDocument.Create( new AetheriaRuntimeRunCheckpointCommit { RunId = "run-soa-frame", CurrentZoneIndex = 2, CurrentEntityKey = "entity:player", Zones = new[] { new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 1, Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 99, PositionX = 999 } } }, new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 2, Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 7, PositionX = 12, PositionY = 3, PositionZ = 34, DirectionX = 1, DirectionY = 0, VelocityX = 5, VelocityY = 6, IsActive = true }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 3, PositionX = -2, PositionY = 4, PositionZ = -8, IsActive = false } } } } }, "aetheria-daemon", "session-soa-frame", 44, 1.0, 0.02); var view = AetheriaRuntimeDaemonSoaFramePublisher.PublishCurrentZoneEntities(statePath, frame); Assert.IsTrue(AetheriaRuntimeDaemonSoaViewStore.TryReadView(statePath, out var stored)); Assert.AreEqual(view.Generation, stored.Generation); Assert.AreEqual(AetheriaRuntimeDaemonSoaBackends.MemoryMappedFile, stored.Backend); Assert.AreEqual(1, stored.Buffers.Count); Assert.IsFalse(stored.Buffers[0].ObserverWritable); Assert.AreEqual(11, stored.Columns.Count); Assert.AreEqual(1, stored.RenderGroups.Count); Assert.AreEqual(2, stored.RenderGroups[0].InstanceCount); var index = AetheriaRuntimeDaemonSoaViewIndex.Build(stored); Assert.IsTrue(index.IsValid, string.Join("\n", index.ValidationErrors)); Assert.IsTrue(index.TryGetFirstColumnOfKind(AetheriaRuntimeDaemonSoaColumnKinds.EntityIndex, out var entityIndex)); Assert.IsTrue(index.TryGetFirstColumnOfKind(AetheriaRuntimeDaemonSoaColumnKinds.Position, out var position)); Assert.IsTrue(index.TryGetFirstColumnOfKind(AetheriaRuntimeDaemonSoaColumnKinds.Velocity, out var velocity)); Assert.IsTrue(index.TryGetFirstColumnOfKind(AetheriaRuntimeDaemonSoaColumnKinds.RenderVisibility, out var visibility)); using var memory = MemoryMappedFile.OpenExisting(stored.Buffers[0].Location, MemoryMappedFileRights.Read); using var accessor = memory.CreateViewAccessor(0, stored.Buffers[0].ByteLength, MemoryMappedFileAccess.Read); Assert.AreEqual(3, accessor.ReadInt32(entityIndex.AbsoluteByteOffset)); Assert.AreEqual(7, accessor.ReadInt32(entityIndex.AbsoluteByteOffset + entityIndex.Column.ElementStride)); Assert.AreEqual(-2f, accessor.ReadSingle(position.AbsoluteByteOffset), 0.0001f); Assert.AreEqual(-8f, accessor.ReadSingle(position.AbsoluteByteOffset + 8), 0.0001f); Assert.AreEqual(12f, accessor.ReadSingle(position.AbsoluteByteOffset + position.Column.ElementStride), 0.0001f); Assert.AreEqual(34f, accessor.ReadSingle(position.AbsoluteByteOffset + position.Column.ElementStride + 8), 0.0001f); Assert.AreEqual(6f, accessor.ReadSingle(velocity.AbsoluteByteOffset + velocity.Column.ElementStride + 8), 0.0001f); Assert.AreEqual(0, accessor.ReadByte(visibility.AbsoluteByteOffset)); Assert.AreEqual(1, accessor.ReadByte(visibility.AbsoluteByteOffset + visibility.Column.ElementStride)); } [Test] public void SoaViewStoreReportsMissingView() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-soa-view-store-tests", Path.GetRandomFileName(), "missing-state.cc"); Assert.IsFalse(AetheriaRuntimeDaemonSoaViewStore.TryReadView(statePath, out _)); } [Test] public void StateReaderReadsObservedDaemonStateWithSoaView() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-observed-daemon-state-tests", Path.GetRandomFileName(), "state.cc"); var frame = AetheriaRuntimeDaemonFrameDocument.Create( new AetheriaRuntimeRunCheckpointCommit { RunId = "daemon-run", CurrentZoneIndex = 2, CurrentEntityKey = "entity:observer-target" }, "aetheria-daemon", "session-observed", 300, 12.0, 0.02); var soaView = AetheriaRuntimeDaemonSoaViewDocument.Create( "aetheria-daemon", "session-observed", 300, 301, new[] { new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "entity-hot", Backend = AetheriaRuntimeDaemonSoaBackends.CultCache, Location = "cultcache://aetheria/run/daemon-run/entity-hot", ByteLength = 1024, Generation = 301, DaemonWritable = true, ObserverWritable = false } }, new[] { new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "position", Kind = AetheriaRuntimeDaemonSoaColumnKinds.Position, BufferId = "entity-hot", ScalarType = "float3", ElementStride = 12, ElementCount = 64 } }); PublishLatestFrameThroughVerseClient(statePath, frame); AetheriaRuntimeDaemonSoaViewStore.PublishView(statePath, soaView); var read = AetheriaRuntimeStateReader.TryReadObservedDaemonState(statePath, out var observed); Assert.IsTrue(read); Assert.IsTrue(observed.IsAuthoritative); Assert.IsTrue(observed.HasSoaView); Assert.AreEqual("daemon-run", observed.Run.RunId); Assert.AreEqual("entity:observer-target", observed.Run.CurrentEntityKey); Assert.AreEqual(300, observed.Frame.FrameId); Assert.AreEqual(301, observed.SoaView.Generation); Assert.AreEqual(AetheriaRuntimeStateBoundary.GetDaemonFramePath(statePath), observed.FramePath); Assert.AreEqual(AetheriaRuntimeStateBoundary.GetDaemonSoaViewPath(statePath), observed.SoaViewPath); Assert.IsFalse(observed.SoaView.Buffers[0].ObserverWritable); } [Test] public void StateReaderReportsMissingObservedDaemonState() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-observed-daemon-state-tests", Path.GetRandomFileName(), "missing-state.cc"); var read = AetheriaRuntimeStateReader.TryReadObservedDaemonState(statePath, out var observed); Assert.IsFalse(read); Assert.IsFalse(observed.IsAuthoritative); Assert.IsFalse(observed.HasSoaView); Assert.AreEqual("missing", observed.Frame.StateSource); Assert.AreEqual(AetheriaRuntimeStateBoundary.GetDaemonFramePath(statePath), observed.FramePath); } [Test] public void ObservationCursorTracksFrameAndSoaGenerationChanges() { var cursor = new AetheriaRuntimeDaemonObservationCursor(); var observed = ObservedState(frameId: 10, soaGeneration: 20); var first = cursor.Observe(observed); var second = cursor.Observe(observed); var third = cursor.Observe(ObservedState(frameId: 11, soaGeneration: 20)); var fourth = cursor.Observe(ObservedState(frameId: 11, soaGeneration: 21)); Assert.IsTrue(first.Observed); Assert.IsTrue(first.FrameChanged); Assert.IsTrue(first.SoaViewChanged); Assert.AreEqual(10, first.FrameId); Assert.AreEqual(20, first.SoaGeneration); Assert.IsFalse(second.Changed); Assert.IsTrue(third.FrameChanged); Assert.IsFalse(third.SoaViewChanged); Assert.IsFalse(fourth.FrameChanged); Assert.IsTrue(fourth.SoaViewChanged); Assert.AreEqual(11, cursor.LastFrameId); Assert.AreEqual(21, cursor.LastSoaGeneration); } [Test] public void ObservationCursorResetForgetsDaemonState() { var cursor = new AetheriaRuntimeDaemonObservationCursor(); cursor.Observe(ObservedState(frameId: 12, soaGeneration: 22)); cursor.Reset(); var missing = cursor.Observe(null); Assert.AreEqual(-1, cursor.LastFrameId); Assert.AreEqual(-1, cursor.LastSoaGeneration); Assert.IsFalse(missing.Observed); Assert.IsFalse(missing.Changed); } [Test] public void CommandClientSendsCommandAgainstObservedDaemonFrame() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-command-client-tests", Path.GetRandomFileName(), "state.cc"); var observed = ObservedState(frameId: 33, soaGeneration: 44); observed.Frame.SessionId = "session-command-client"; observed.Frame.Run.CurrentEntityKey = "entity:player"; var client = new AetheriaRuntimeDaemonOperationClient(statePath, "unity-test", "unobserved-session"); var envelope = client.FireWeaponGroup(observed, 2); Assert.AreEqual(AetheriaRuntimeDaemonCommandKinds.FireWeaponGroup, envelope.Kind); Assert.AreEqual("unity-test", envelope.ClientId); Assert.AreEqual("session-command-client", envelope.SessionId); Assert.AreEqual(33, envelope.ObservedFrameId); Assert.AreEqual("entity:player", envelope.ActorEntityKey); Assert.IsEmpty(envelope.Path); } [Test] public void CommandClientUsesRuntimeNeutralDefaultClientId() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-command-client-tests", Path.GetRandomFileName(), "state.cc"); var observed = ObservedState(frameId: 34, soaGeneration: 45); var client = new AetheriaRuntimeDaemonOperationClient(statePath, "", "session-default-client"); var envelope = client.SensorPing(observed); Assert.AreEqual(AetheriaRuntimeDaemonOperationClient.DefaultClientId, envelope.ClientId); Assert.AreEqual(AetheriaRuntimeDaemonCommandKinds.SensorPing, envelope.Kind); } [Test] public void DaemonEveSurfaceCommandSubmitsTypedDaemonOperation() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-surface-command-tests", Path.GetRandomFileName(), "state.cc"); var frame = AetheriaRuntimeDaemonFrameDocument.Create( new AetheriaRuntimeRunCheckpointCommit { CurrentEntityKey = "entity:surface-player" }, "aetheria-daemon", "session-surface-command", 77, 1.5, 0.02); PublishLatestFrameThroughVerseClient(statePath, frame); var request = new EveSurfaceCommandRequest( "aetheria.daemon", AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, CultMesh.OperationInvocation("aetheria.daemon.commands.FireWeaponGroup"), CultMesh.OperationPayload(), DateTimeOffset.UtcNow, "unity-uitoolkit"); Assert.IsTrue(AetheriaRuntimeDaemonSurfaceCommands.TrySubmit(statePath, request, out var envelope)); Assert.AreEqual(AetheriaRuntimeDaemonCommandKinds.FireWeaponGroup, envelope.Kind); Assert.AreEqual("unity-uitoolkit", envelope.ClientId); Assert.AreEqual("session-surface-command", envelope.SessionId); Assert.AreEqual(77, envelope.ObservedFrameId); Assert.AreEqual("entity:surface-player", envelope.ActorEntityKey); Assert.IsEmpty(envelope.Path); } [Test] public void DaemonEveSurfaceCommandUsesRuntimeNeutralDefaultClientId() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-surface-command-tests", Path.GetRandomFileName(), "state.cc"); var frame = AetheriaRuntimeDaemonFrameDocument.Create( new AetheriaRuntimeRunCheckpointCommit { CurrentEntityKey = "entity:surface-player" }, "aetheria-daemon", "session-surface-command", 79, 1.5, 0.02); PublishLatestFrameThroughVerseClient(statePath, frame); var request = new EveSurfaceCommandRequest( "aetheria.daemon", AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, CultMesh.OperationInvocation("aetheria.daemon.commands.SensorPing"), CultMesh.OperationPayload(), DateTimeOffset.UtcNow, ""); Assert.IsTrue(AetheriaRuntimeDaemonSurfaceCommands.TrySubmit(statePath, request, out var envelope)); Assert.AreEqual(AetheriaRuntimeDaemonOperationClient.DefaultClientId, envelope.ClientId); Assert.AreEqual(AetheriaRuntimeDaemonCommandKinds.SensorPing, envelope.Kind); } [Test] public void DaemonEveSurfaceCommandRejectsUnsupportedArgumentlessOperation() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-surface-command-tests", Path.GetRandomFileName(), "state.cc"); var frame = AetheriaRuntimeDaemonFrameDocument.Create( new AetheriaRuntimeRunCheckpointCommit { CurrentEntityKey = "entity:surface-player" }, "aetheria-daemon", "session-surface-command", 78, 1.5, 0.02); AetheriaRuntimeDaemonFrameStore.PublishFrame(statePath, frame); var request = new EveSurfaceCommandRequest( "aetheria.daemon", AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, CultMesh.OperationInvocation("aetheria.daemon.commands.TransferCargoItem"), CultMesh.OperationPayload(), DateTimeOffset.UtcNow, "unity-uitoolkit"); Assert.IsFalse(AetheriaRuntimeDaemonSurfaceCommands.TrySubmit(statePath, request, out var envelope)); Assert.IsNull(envelope); } [Test] public void DaemonItemStatRefsRoundTripThroughSharedQueryHelper() { var stateRef = AetheriaRuntimeDaemonItemStatQueries.ItemStatRef( "items/weapons/mining-laser", "behavior/mining", 2, 7); Assert.IsTrue(AetheriaRuntimeDaemonItemStatQueries.TryReadItemStatRef( stateRef, out var itemKey, out var behaviorKind, out var behaviorGroup, out var fieldKey)); Assert.AreEqual("items/weapons/mining-laser", itemKey); Assert.AreEqual("behavior/mining", behaviorKind); Assert.AreEqual(2, behaviorGroup); Assert.AreEqual(7, fieldKey); } [Test] public void DaemonOperationsMovesTargetSelectionIntoDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetTarget, "codex", "session-target", 15, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.1"; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(0, result.RejectedCommandIds.Count); Assert.AreEqual(1, run.Zones[0].Entities[0].TargetEntityIndex); } [Test] public void DaemonOperationsRejectsTargetSelectionWithoutVisibleContact() { var run = RunWithTwoEntities(); run.Zones[0].Entities[0].Contacts = Array.Empty(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetTarget, "codex", "session-target", 15, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.1"; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(-1, run.Zones[0].Entities[0].TargetEntityIndex); } [Test] public void DaemonOperationsCyclesTargetsFromAuthoritativeContacts() { var run = RunWithTwoEntities(); var zone = run.Zones[0]; zone.Entities[0].PositionX = 0; zone.Entities[0].PositionY = 0; zone.Entities[1].PositionX = 5; zone.Entities[1].PositionY = 0; zone.Entities = zone.Entities .Concat(new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 2, Name = "Near Hostile", PositionX = 2, PositionY = 0 } }) .ToArray(); zone.Entities[0].Contacts = new[] { new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 1, Visible = true, Hostile = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 2, Visible = true, Hostile = true } }; var nearest = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TargetNearest, "codex", "session-target", 15, "zone.0.entity.0"); var next = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TargetNext, "codex", "session-target", 16, "zone.0.entity.0"); var previous = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TargetPrevious, "codex", "session-target", 17, "zone.0.entity.0"); var previousFromNoneResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { previous }); Assert.AreEqual(1, previousFromNoneResult.AppliedCommandIds.Count); Assert.AreEqual(2, zone.Entities[0].TargetEntityIndex); var nearestResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { nearest }); Assert.AreEqual(1, nearestResult.AppliedCommandIds.Count); Assert.AreEqual(2, zone.Entities[0].TargetEntityIndex); var nextResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { next }); Assert.AreEqual(1, nextResult.AppliedCommandIds.Count); Assert.AreEqual(1, zone.Entities[0].TargetEntityIndex); var previousResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { previous }); Assert.AreEqual(1, previousResult.AppliedCommandIds.Count); Assert.AreEqual(2, zone.Entities[0].TargetEntityIndex); } [Test] public void DaemonOperationsTargetsReticleFromAuthoritativeContacts() { var run = RunWithTwoEntities(); var zone = run.Zones[0]; zone.Entities[0].PositionX = 0; zone.Entities[0].PositionY = 0; zone.Entities[0].PositionZ = 0; zone.Entities[1].PositionX = 0; zone.Entities[1].PositionY = 0; zone.Entities[1].PositionZ = 5; zone.Entities = zone.Entities .Concat(new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 2, Name = "Off Reticle", PositionX = 5, PositionY = 0, PositionZ = 0 } }) .ToArray(); zone.Entities[0].Contacts = new[] { new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 1, Visible = true, Hostile = true }, new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 2, Visible = true, Hostile = true } }; var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TargetReticle, "codex", "session-reticle", 18, "zone.0.entity.0"); command.PositionZ = 1; var targetResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(1, targetResult.AppliedCommandIds.Count); Assert.AreEqual(1, zone.Entities[0].TargetEntityIndex); var toggleResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(1, toggleResult.AppliedCommandIds.Count); Assert.AreEqual(-1, zone.Entities[0].TargetEntityIndex); } [Test] public void DaemonOperationsMutatesHotEntityControlsInDaemonState() { var run = RunWithTwoEntities(); var look = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetLookDirection, "codex", "session-controls", 16, "zone.0.entity.0"); look.DirectionX = 0.25; look.PositionZ = -0.75; var tractor = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetTractorPower, "codex", "session-controls", 16, "zone.0.entity.0"); tractor.ScalarValue = 0.8; var heatsinks = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetHeatsinksEnabled, "codex", "session-controls", 16, "zone.0.entity.0"); heatsinks.ScalarValue = 1.0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { look, tractor, heatsinks }); var player = run.Zones[0].Entities[0]; Assert.AreEqual(3, result.AppliedCommandIds.Count); Assert.AreEqual(0, result.RejectedCommandIds.Count); Assert.AreEqual(0.25, player.DirectionX, 0.0001); Assert.AreEqual(-0.75, player.DirectionY, 0.0001); Assert.AreEqual(0.8, player.TractorPower, 0.0001); Assert.IsTrue(player.HeatsinksEnabled); } [Test] public void DaemonOperationsRejectsOutOfRangeTractorPower() { var run = RunWithTwoEntities(); var tractor = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetTractorPower, "codex", "session-controls", 16, "zone.0.entity.0"); tractor.ScalarValue = 1.25; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { tractor }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(0.0, run.Zones[0].Entities[0].TractorPower, 0.0001); } [Test] public void DaemonOperationsRejectsOutOfRangeMoveMagnitude() { var run = RunWithTwoEntities(); var move = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetMoveVector, "codex", "session-intents", 32, "zone.0.entity.0"); move.DirectionX = 0.25; move.DirectionY = -0.5; move.ScalarValue = 1.25; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { move }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.IsFalse(result.Intents.HasAny); } [Test] public void DaemonCommandSchemaDoesNotOwnActionBarBindings() { var commandNames = Enum.GetNames(typeof(AetheriaRuntimeDaemonCommandKinds)); var boundary = AetheriaRuntimeDaemonCommandBoundaryDocument.Create("codex"); var commandBodies = boundary.Commands .Select(command => command.CommandBody) .ToArray(); Assert.IsFalse(commandNames.Contains("SetActionBarBinding")); Assert.IsFalse(commandNames.Contains("ClearActionBarBinding")); Assert.IsFalse(commandBodies.Contains("AetheriaRuntimeActionBarBindingCommand")); } [Test] public void DaemonOperationsOwnsEquipmentSwitchesInDaemonState() { var run = RunWithTwoEntities(); var disable = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetItemEnabled, "codex", "session-equipment", 19, "zone.0.entity.0"); disable.EquipmentIndex = 0; disable.ScalarValue = 0.0; var overrideShutdown = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetItemOverrideShutdown, "codex", "session-equipment", 20, "zone.0.entity.0"); overrideShutdown.TargetEntityKey = "zone.0.entity.0"; overrideShutdown.EquipmentIndex = 0; overrideShutdown.ScalarValue = 1.0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { disable, overrideShutdown }); var item = run.Zones[0].Entities[0].Equipment[0].Item; Assert.AreEqual(2, result.AppliedCommandIds.Count); Assert.IsFalse(item.Enabled); Assert.IsTrue(item.OverrideShutdown); } [Test] public void DaemonOperationsOwnsShieldToggleSelectionInDaemonState() { var run = RunWithTwoEntities(); var toggle = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.ToggleShieldEnabled, "codex", "session-equipment", 21, "zone.0.entity.0"); var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { toggle }); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.IsFalse(run.Zones[0].Entities[0].Equipment[1].Item.Enabled); } [Test] public void DaemonOperationsRejectsShieldToggleWhenNoShieldBehaviorExists() { var run = RunWithTwoEntities(); run.Zones[0].Entities[0].BehaviorStates = Array.Empty(); var toggle = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.ToggleShieldEnabled, "codex", "session-equipment", 21, "zone.0.entity.0"); var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { toggle }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.IsTrue(run.Zones[0].Entities[0].Equipment[1].Item.Enabled); } [Test] public void DaemonOperationsOwnsWeaponGroupMembershipInDaemonState() { var run = RunWithTwoEntities(); var add = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetWeaponGroupMembership, "codex", "session-weapon-groups", 21, "zone.0.entity.0"); add.TargetEntityKey = "zone.0.entity.0"; add.EquipmentIndex = 1; add.WeaponGroup = 0; add.ScalarValue = 1.0; var remove = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetWeaponGroupMembership, "codex", "session-weapon-groups", 22, "zone.0.entity.0"); remove.TargetEntityKey = "zone.0.entity.0"; remove.EquipmentIndex = 0; remove.WeaponGroup = 0; remove.ScalarValue = 0.0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { add, remove }); Assert.AreEqual(2, result.AppliedCommandIds.Count); CollectionAssert.AreEqual(new[] { 1 }, run.Zones[0].Entities[0].WeaponGroups[0]); } [Test] public void DaemonOperationsRejectsInvalidWeaponGroupMembership() { var run = RunWithTwoEntities(); var missingEquipment = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetWeaponGroupMembership, "codex", "session-weapon-groups", 21, "zone.0.entity.0"); missingEquipment.TargetEntityKey = "zone.0.entity.0"; missingEquipment.EquipmentIndex = 99; missingEquipment.WeaponGroup = 0; missingEquipment.ScalarValue = 1.0; var negativeGroup = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetWeaponGroupMembership, "codex", "session-weapon-groups", 22, "zone.0.entity.0"); negativeGroup.TargetEntityKey = "zone.0.entity.0"; negativeGroup.EquipmentIndex = 1; negativeGroup.WeaponGroup = -1; negativeGroup.ScalarValue = 1.0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { missingEquipment, negativeGroup }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(2, result.RejectedCommandIds.Count); CollectionAssert.AreEqual(new[] { 0 }, run.Zones[0].Entities[0].WeaponGroups[0]); } [Test] public void DaemonOperationsOwnsThermotoggleTargetInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetThermotoggleTargetTemperature, "codex", "session-thermotoggle", 23, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.0"; command.EquipmentIndex = 0; command.BehaviorIndex = 0; command.ScalarValue = 450.0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(450.0, run.Zones[0].Entities[0].BehaviorStates[0].ThermotoggleTargetTemperature, 0.0001); } [Test] public void DaemonOperationsTransfersCargoItemsInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TransferCargoItem, "codex", "session-inventory", 24, "zone.0.entity.0"); command.TextValue = "ore"; command.TargetEntityKey = "zone.0.entity.1"; command.PositionX = 5; command.PositionY = 6; command.ScalarValue = 12; command.CargoTransfer.OriginEntityKey = "zone.0.entity.0"; command.CargoTransfer.OriginCargoIndex = 0; command.CargoTransfer.DestinationEntityKey = "zone.0.entity.1"; command.CargoTransfer.DestinationCargoIndex = 0; command.CargoTransfer.SourceX = 2; command.CargoTransfer.SourceY = 3; command.CargoTransfer.DestinationX = 5; command.CargoTransfer.DestinationY = 6; command.CargoTransfer.HasDestinationPosition = true; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var originCargo = run.Zones[0].Entities[0].CargoContents[0].Items; var destinationCargo = run.Zones[0].Entities[1].CargoContents[0].Items; Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(0, originCargo.Count); Assert.AreEqual(1, destinationCargo.Count); Assert.AreEqual("ore", destinationCargo[0].Item.ItemKey); Assert.AreEqual(5, destinationCargo[0].X); Assert.AreEqual(6, destinationCargo[0].Y); } [Test] public void DaemonOperationsRejectsSameCargoTransferWithoutReposition() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TransferCargoItem, "codex", "session-inventory", 24, "zone.0.entity.0"); command.TextValue = "ore"; command.CargoTransfer.OriginEntityKey = "zone.0.entity.0"; command.CargoTransfer.OriginCargoIndex = 0; command.CargoTransfer.DestinationEntityKey = "zone.0.entity.0"; command.CargoTransfer.DestinationCargoIndex = 0; command.CargoTransfer.SourceX = 2; command.CargoTransfer.SourceY = 3; command.CargoTransfer.HasDestinationPosition = false; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var cargo = run.Zones[0].Entities[0].CargoContents[0].Items; Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(1, cargo.Count); Assert.AreEqual(2, cargo[0].X); Assert.AreEqual(3, cargo[0].Y); } [Test] public void DaemonOperationsRepositionsCargoItemWithinSameCargoBay() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TransferCargoItem, "codex", "session-inventory", 24, "zone.0.entity.0"); command.TextValue = "ore"; command.CargoTransfer.OriginEntityKey = "zone.0.entity.0"; command.CargoTransfer.OriginCargoIndex = 0; command.CargoTransfer.DestinationEntityKey = "zone.0.entity.0"; command.CargoTransfer.DestinationCargoIndex = 0; command.CargoTransfer.SourceX = 2; command.CargoTransfer.SourceY = 3; command.CargoTransfer.DestinationX = 6; command.CargoTransfer.DestinationY = 7; command.CargoTransfer.HasDestinationPosition = true; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var cargo = run.Zones[0].Entities[0].CargoContents[0].Items; Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(1, cargo.Count); Assert.AreEqual(6, cargo[0].X); Assert.AreEqual(7, cargo[0].Y); } [Test] public void DaemonOperationsResolvesCargoSourcePositionWhenClientOmitsIt() { var run = RunWithTwoEntities(); var transfer = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TransferCargoItem, "codex", "session-inventory", 31, "zone.0.entity.0"); transfer.TextValue = "ore"; transfer.CargoTransfer.OriginEntityKey = "zone.0.entity.0"; transfer.CargoTransfer.OriginCargoIndex = 0; transfer.CargoTransfer.DestinationEntityKey = "zone.0.entity.1"; transfer.CargoTransfer.DestinationCargoIndex = 0; transfer.CargoTransfer.SourceX = int.MinValue; transfer.CargoTransfer.SourceY = int.MinValue; var transferResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { transfer }); Assert.AreEqual(1, transferResult.AppliedCommandIds.Count); Assert.AreEqual(0, run.Zones[0].Entities[0].CargoContents[0].Items.Count); Assert.AreEqual("ore", run.Zones[0].Entities[1].CargoContents[0].Items[0].Item.ItemKey); var equip = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.EquipItem, "codex", "session-inventory", 32, "zone.0.entity.0"); equip.TextValue = "ore"; equip.EquipmentTransfer.SourceKind = "cargo"; equip.EquipmentTransfer.OriginEntityKey = "zone.0.entity.1"; equip.EquipmentTransfer.OriginIndex = 0; equip.EquipmentTransfer.DestinationEntityKey = "zone.0.entity.0"; equip.EquipmentTransfer.SourceX = int.MinValue; equip.EquipmentTransfer.SourceY = int.MinValue; var equipResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { equip }); Assert.AreEqual(1, equipResult.AppliedCommandIds.Count); Assert.AreEqual(3, run.Zones[0].Entities[0].Equipment.Count); Assert.AreEqual("ore", run.Zones[0].Entities[0].Equipment[2].Item.ItemKey); Assert.AreEqual(0, run.Zones[0].Entities[1].CargoContents[0].Items.Count); } [Test] public void DaemonOperationsEquipsCargoItemInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.EquipItem, "codex", "session-inventory", 25, "zone.0.entity.0"); command.TextValue = "ore"; command.TargetEntityKey = "zone.0.entity.0"; command.EquipmentTransfer.SourceKind = "cargo"; command.EquipmentTransfer.OriginEntityKey = "zone.0.entity.0"; command.EquipmentTransfer.OriginIndex = 0; command.EquipmentTransfer.DestinationEntityKey = "zone.0.entity.0"; command.EquipmentTransfer.SourceX = 2; command.EquipmentTransfer.SourceY = 3; command.EquipmentTransfer.DestinationX = 8; command.EquipmentTransfer.DestinationY = 9; command.EquipmentTransfer.HasDestinationPosition = true; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var entity = run.Zones[0].Entities[0]; Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(0, entity.CargoContents[0].Items.Count); Assert.AreEqual(3, entity.Equipment.Count); Assert.AreEqual("ore", entity.Equipment[2].Item.ItemKey); Assert.AreEqual(8, entity.Equipment[2].X); Assert.AreEqual(9, entity.Equipment[2].Y); } [Test] public void DaemonOperationsStoresEquipmentItemInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.StoreItem, "codex", "session-inventory", 26, "zone.0.entity.0"); command.TextValue = "laser"; command.StoreItem.OriginEntityKey = "zone.0.entity.0"; command.StoreItem.SourceEquipmentIndex = 1; command.StoreItem.DestinationEntityKey = "zone.0.entity.1"; command.StoreItem.DestinationCargoIndex = 0; command.StoreItem.DestinationX = 4; command.StoreItem.DestinationY = 7; command.StoreItem.HasDestinationPosition = true; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var origin = run.Zones[0].Entities[0]; var destinationCargo = run.Zones[0].Entities[1].CargoContents[0].Items; Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(1, origin.Equipment.Count); Assert.AreEqual(1, destinationCargo.Count); Assert.AreEqual("laser", destinationCargo[0].Item.ItemKey); Assert.AreEqual(4, destinationCargo[0].X); Assert.AreEqual(7, destinationCargo[0].Y); CollectionAssert.IsEmpty(origin.WeaponGroups[0]); } [Test] public void DaemonOperationsRejectsStoreItemWhenEquipmentSourceDoesNotMatch() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.StoreItem, "codex", "session-inventory", 26, "zone.0.entity.0"); command.TextValue = "laser"; command.StoreItem.OriginEntityKey = "zone.0.entity.0"; command.StoreItem.SourceEquipmentIndex = 0; command.StoreItem.DestinationEntityKey = "zone.0.entity.1"; command.StoreItem.DestinationCargoIndex = 0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(2, run.Zones[0].Entities[0].Equipment.Count); Assert.AreEqual(0, run.Zones[0].Entities[1].CargoContents[0].Items.Count); } [Test] public void DaemonOperationsRejectsEquipItemWhenEquipmentSourceDoesNotMatch() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.EquipItem, "codex", "session-inventory", 26, "zone.0.entity.0"); command.TextValue = "laser"; command.EquipmentTransfer.SourceKind = "equipment"; command.EquipmentTransfer.OriginEntityKey = "zone.0.entity.0"; command.EquipmentTransfer.OriginIndex = 0; command.EquipmentTransfer.DestinationEntityKey = "zone.0.entity.1"; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(2, run.Zones[0].Entities[0].Equipment.Count); Assert.AreEqual(0, run.Zones[0].Entities[1].Equipment.Count); } [Test] public void DaemonOperationsPicksUpLootInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.PickUpLoot, "codex", "session-loot", 27, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.0"; command.TextValue = "loot-cell"; command.PositionX = 10; command.PositionY = 11; command.PositionZ = 12; command.ScalarValue = 1; command.LootPickup.ItemKey = "loot-cell"; command.LootPickup.Quantity = 1; command.LootPickup.PositionX = 10; command.LootPickup.PositionY = 11; command.LootPickup.PositionZ = 12; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var zone = run.Zones[0]; var cargo = zone.Entities[0].CargoContents[0].Items; Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(0, zone.DroppedPickups.Count); Assert.AreEqual(2, cargo.Count); Assert.AreEqual("loot-cell", cargo[1].Item.ItemKey); } [Test] public void DaemonOperationsTogglesHullConductivityInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.ToggleHullConductivity, "codex", "session-hull", 28, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.0"; command.PositionX = 1; command.PositionY = 0; command.ScalarValue = 0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var grid = run.Zones[0].Entities[0].StatGrids[0]; Assert.AreEqual(1, result.AppliedCommandIds.Count); CollectionAssert.AreEqual(new[] { 1.0, 1.0, 0.0, 1.0 }, grid.Values); } [Test] public void DaemonOperationsRejectsInvalidHullConductivityToggle() { var outOfRange = RunWithTwoEntities(); var invalidPosition = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.ToggleHullConductivity, "codex", "session-hull", 29, "zone.0.entity.0"); invalidPosition.TargetEntityKey = "zone.0.entity.0"; invalidPosition.PositionX = 99; invalidPosition.PositionY = 0; invalidPosition.ScalarValue = 0; var outOfRangeResult = AetheriaRuntimeDaemonOperations.Execute(outOfRange, new[] { invalidPosition }); Assert.AreEqual(0, outOfRangeResult.AppliedCommandIds.Count); Assert.AreEqual(1, outOfRangeResult.RejectedCommandIds.Count); CollectionAssert.AreEqual(new[] { 1.0, 0.0, 0.0, 1.0 }, outOfRange.Zones[0].Entities[0].StatGrids[0].Values); var invalidAxis = RunWithTwoEntities(); var invalidAxisCommand = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.ToggleHullConductivity, "codex", "session-hull", 30, "zone.0.entity.0"); invalidAxisCommand.TargetEntityKey = "zone.0.entity.0"; invalidAxisCommand.PositionX = 1; invalidAxisCommand.PositionY = 0; invalidAxisCommand.ScalarValue = 2; var invalidAxisResult = AetheriaRuntimeDaemonOperations.Execute(invalidAxis, new[] { invalidAxisCommand }); Assert.AreEqual(0, invalidAxisResult.AppliedCommandIds.Count); Assert.AreEqual(1, invalidAxisResult.RejectedCommandIds.Count); CollectionAssert.AreEqual(new[] { 1.0, 0.0, 0.0, 1.0 }, invalidAxis.Zones[0].Entities[0].StatGrids[0].Values); } [Test] public void DaemonOperationsOwnsShutdownPerformanceInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetShutdownPerformance, "codex", "session-shutdown-performance", 29, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.0"; command.ScalarValue = 0.375; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(0.375, run.Zones[0].Entities[0].ShutdownPerformance, 0.0001); } [Test] public void DaemonOperationsRejectsOutOfRangeShutdownPerformance() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetShutdownPerformance, "codex", "session-shutdown-performance", 29, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.0"; command.ScalarValue = 1.5; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(0.25, run.Zones[0].Entities[0].ShutdownPerformance, 0.0001); } [Test] public void DaemonOperationsOwnsTradePurchaseCreditsAndCargoInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TradePurchase, "codex", "session-trade", 30, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.1"; command.TextValue = "ore"; command.ScalarValue = 200; command.TradePurchase.PurchaseKind = "commodity"; command.TradePurchase.ItemKey = "ore"; command.TradePurchase.Quantity = 5; command.TradePurchase.UnitPrice = 40; command.TradePurchase.TotalPrice = 200; command.TradePurchase.StationEntityKey = "zone.0.entity.0"; command.TradePurchase.StationCargoIndex = 0; command.TradePurchase.TargetEntityKey = "zone.0.entity.1"; command.TradePurchase.TargetCargoIndex = 0; command.TradePurchase.SourceX = 2; command.TradePurchase.SourceY = 3; command.TradePurchase.CreatesDockedShip = false; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var stationCargo = run.Zones[0].Entities[0].CargoContents[0].Items; var targetCargo = run.Zones[0].Entities[1].CargoContents[0].Items; Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(800, run.Credits); Assert.AreEqual(1, stationCargo.Count); Assert.AreEqual(7, stationCargo[0].Item.Quantity); Assert.AreEqual(1, targetCargo.Count); Assert.AreEqual("ore", targetCargo[0].Item.ItemKey); Assert.AreEqual(5, targetCargo[0].Item.Quantity); } [Test] public void DaemonOperationsCreatesPurchasedDockedShipInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TradePurchase, "codex", "session-trade", 31, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.1"; command.TextValue = "starter-hull"; command.ScalarValue = 300; command.TradePurchase.PurchaseKind = "docked_ship"; command.TradePurchase.ItemKey = "starter-hull"; command.TradePurchase.Quantity = 1; command.TradePurchase.UnitPrice = 300; command.TradePurchase.TotalPrice = 300; command.TradePurchase.TargetEntityKey = "zone.0.entity.1"; command.TradePurchase.CreatesDockedShip = true; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var zone = run.Zones[0]; Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(700, run.Credits); Assert.AreEqual(3, zone.Entities.Count); Assert.AreEqual("ship", zone.Entities[2].Kind); Assert.AreEqual("starter-hull", zone.Entities[2].HullItemKey); CollectionAssert.Contains(zone.Entities[1].ChildEntityIndices, 2); CollectionAssert.Contains(zone.Entities[1].DockingBayAssignments, 2); Assert.AreEqual("global:aetheria.run_state.daemon-command-apply-run.zone.0.entity.2.v1", run.CurrentEntityKey); } [Test] public void DaemonOperationsRestoresLoadoutIntoDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.RestoreLoadout, "codex", "session-loadout", 31, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.0"; command.TextValue = "Starter"; command.ScalarValue = 250; command.LoadoutRestore.DockedEntityKey = "zone.0.entity.0"; command.LoadoutRestore.TemplateName = "Starter"; command.LoadoutRestore.Price = 250; var result = AetheriaRuntimeDaemonOperations.Execute( run, new[] { command }, new AetheriaRuntimeDaemonOperationContext { LoadoutTemplates = new[] { new AetheriaRuntimeLoadoutTemplateCommit { Name = "Starter", RootEntity = new AetheriaRuntimeEntityLoadoutCommit { Name = "Starter Ship", Kind = "ship", Hull = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "starter-hull" }, Equipment = new[] { new AetheriaRuntimeLoadoutItemSlotCommit { X = 1, Y = 2, Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "starter-reactor" } } }, WeaponGroups = new[] { new[] { 0 } } } } } }); var zone = run.Zones[0]; Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(750, run.Credits); Assert.AreEqual(3, zone.Entities.Count); Assert.AreEqual("Starter Ship", zone.Entities[2].Name); Assert.AreEqual("starter-hull", zone.Entities[2].HullItemKey); Assert.AreEqual("starter-reactor", zone.Entities[2].Equipment[0].Item.ItemKey); CollectionAssert.Contains(zone.Entities[0].ChildEntityIndices, 2); Assert.AreEqual("global:aetheria.run_state.daemon-command-apply-run.zone.0.entity.2.v1", run.CurrentEntityKey); } [Test] public void DaemonOperationsRejectsMissingLoadoutTemplateWithoutChargingCredits() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.RestoreLoadout, "codex", "session-loadout", 32, "zone.0.entity.0"); command.TargetEntityKey = "zone.0.entity.0"; command.TextValue = "Missing"; command.ScalarValue = 250; command.LoadoutRestore.DockedEntityKey = "zone.0.entity.0"; command.LoadoutRestore.TemplateName = "Missing"; command.LoadoutRestore.Price = 250; var result = AetheriaRuntimeDaemonOperations.Execute( run, new[] { command }, new AetheriaRuntimeDaemonOperationContext { LoadoutTemplates = Array.Empty() }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(1000, run.Credits); Assert.AreEqual(2, run.Zones[0].Entities.Count); Assert.AreEqual("global:aetheria.run_state.daemon-command-apply-run.zone.0.entity.0.v1", run.CurrentEntityKey); } [Test] public void DaemonOperationsDestroysEntityInDaemonState() { var run = RunWithTwoEntities(); run.CurrentEntityKey = "zone.0.entity.1"; run.Zones[0].Entities[0].TargetEntityIndex = 1; run.Zones[0].Entities[0].ChildEntityIndices = new[] { 1 }; run.Zones[0].Entities[0].DockingBayAssignments = new[] { 1, -1 }; run.Zones[0].Entities[0].Contacts = new[] { new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 1, Visible = true } }; run.Zones[0].Entities = new[] { run.Zones[0].Entities[0], run.Zones[0].Entities[1], new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 2, Name = "Reindexed" } }; var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.DestroyEntity, "codex", "session-destroy", 44, ""); command.TargetEntityKey = "zone.0.entity.1"; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(2, run.Zones[0].Entities.Count); Assert.AreEqual("Player", run.Zones[0].Entities[0].Name); Assert.AreEqual(0, run.Zones[0].Entities[0].EntityIndex); Assert.AreEqual("Reindexed", run.Zones[0].Entities[1].Name); Assert.AreEqual(1, run.Zones[0].Entities[1].EntityIndex); Assert.AreEqual(-1, run.Zones[0].Entities[0].TargetEntityIndex); Assert.AreEqual(0, run.Zones[0].Entities[0].ChildEntityIndices.Count); Assert.AreEqual(-1, run.Zones[0].Entities[0].DockingBayAssignments[0]); Assert.AreEqual(-1, run.Zones[0].Entities[0].DockingBayAssignments[1]); Assert.AreEqual(0, run.Zones[0].Entities[0].Contacts.Count); Assert.AreEqual("", run.CurrentEntityKey); } [Test] public void DaemonOperationsMovesEntityThroughWormholeInDaemonState() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.EnterWormhole, "codex", "session-wormhole", 45, "zone.0.entity.0"); command.TargetZoneIndex = 2; command.PositionX = 100; command.PositionY = 200; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var sourceZone = FindZone(run, 0); var targetZone = FindZone(run, 2); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(2, run.CurrentZoneIndex); Assert.AreEqual("global:aetheria.run_state.daemon-command-apply-run.zone.2.entity.0.v1", run.CurrentEntityKey); Assert.AreEqual(1, sourceZone.Entities.Count); Assert.AreEqual("Target", sourceZone.Entities[0].Name); Assert.AreEqual(0, sourceZone.Entities[0].EntityIndex); Assert.AreEqual(1, targetZone.Entities.Count); Assert.AreEqual("Player", targetZone.Entities[0].Name); Assert.AreEqual(0, targetZone.Entities[0].EntityIndex); Assert.AreEqual(100, targetZone.Entities[0].PositionX, 0.0001); Assert.AreEqual(200, targetZone.Entities[0].PositionZ, 0.0001); CollectionAssert.Contains(run.DiscoveredZoneIndices, 2); Assert.AreEqual(1, result.Intents.Wormholes.Count); Assert.AreEqual("global:aetheria.run_state.daemon-command-apply-run.zone.2.entity.0.v1", result.Intents.Wormholes[0].ActorEntityKey); Assert.AreEqual(2, result.Intents.Wormholes[0].TargetZoneIndex); } [Test] public void DaemonOperationsRejectsWormholeMoveWhenEntityIsDocked() { var run = RunWithTwoEntities(); run.Zones[0].Entities[1].ChildEntityIndices = new[] { 0 }; run.Zones[0].Entities[1].DockingBayAssignments = new[] { 0, -1 }; var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.EnterWormhole, "codex", "session-wormhole", 45, "zone.0.entity.0"); command.TargetZoneIndex = 2; command.PositionX = 100; command.PositionY = 200; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(0, result.Intents.Wormholes.Count); Assert.AreEqual(1, run.Zones[0].Entities[1].ChildEntityIndices.Count); CollectionAssert.Contains(run.Zones[0].Entities[1].DockingBayAssignments, 0); } [Test] public void DaemonOperationsInteractPrioritizesUndockWormholeThenDock() { var undockRun = RunWithTwoEntities(); undockRun.Zones[0].Entities[1].ChildEntityIndices = new[] { 0 }; undockRun.Zones[0].Entities[1].DockingBayAssignments = new[] { 0, -1 }; var undock = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.Interact, "codex", "session-interact", 46, "zone.0.entity.0"); undock.ScalarValue = 10; undock.PositionX = 10; var undockResult = AetheriaRuntimeDaemonOperations.Execute(undockRun, new[] { undock }); Assert.AreEqual(1, undockResult.AppliedCommandIds.Count); Assert.AreEqual(1, undockResult.Intents.Docking.Count); Assert.IsTrue(undockResult.Intents.Docking[0].Undock); CollectionAssert.DoesNotContain(undockRun.Zones[0].Entities[1].DockingBayAssignments, 0); var wormholeRun = RunWithTwoEntities(); wormholeRun.Zones[0].AdjacentZoneIndices = new[] { 2 }; wormholeRun.Zones[0].Entities[0].PositionX = 0; wormholeRun.Zones[0].Entities[0].PositionZ = 0; wormholeRun.Zones = wormholeRun.Zones .Concat(new[] { new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 2, PositionX = 3, PositionY = 4 } }) .ToArray(); var wormhole = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.Interact, "codex", "session-interact", 47, "zone.0.entity.0"); wormhole.ScalarValue = 10; wormhole.PositionX = 10; var wormholeResult = AetheriaRuntimeDaemonOperations.Execute(wormholeRun, new[] { wormhole }); Assert.AreEqual(1, wormholeResult.AppliedCommandIds.Count); Assert.AreEqual(1, wormholeResult.Intents.Wormholes.Count); Assert.AreEqual(2, wormholeRun.CurrentZoneIndex); Assert.AreEqual(3, FindZone(wormholeRun, 2).Entities[0].PositionX, 0.0001); Assert.AreEqual(4, FindZone(wormholeRun, 2).Entities[0].PositionZ, 0.0001); var dockRun = RunWithTwoEntities(); dockRun.Zones[0].Entities[0].PositionX = 0; dockRun.Zones[0].Entities[0].PositionY = 0; dockRun.Zones[0].Entities[1].PositionX = 3; dockRun.Zones[0].Entities[1].PositionY = 4; var dock = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.Interact, "codex", "session-interact", 48, "zone.0.entity.0"); dock.ScalarValue = 10; dock.PositionX = 1; var dockResult = AetheriaRuntimeDaemonOperations.Execute(dockRun, new[] { dock }); Assert.AreEqual(1, dockResult.AppliedCommandIds.Count); Assert.AreEqual(1, dockResult.Intents.Docking.Count); Assert.IsTrue(dockResult.Intents.Docking[0].Dock); CollectionAssert.Contains(dockRun.Zones[0].Entities[1].ChildEntityIndices, 0); } [Test] public void DaemonOperationsTowsEntityToStationInDaemonState() { var run = RunWithTwoEntities(); run.Zones = new[] { run.Zones[0], new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 3, Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 0, Name = "Tow Station", PositionX = 300, PositionZ = 400 } } } }; var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.TowToStation, "codex", "session-towing", 46, "zone.0.entity.0"); command.TargetEntityKey = "zone.3.entity.0"; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); var sourceZone = FindZone(run, 0); var targetZone = FindZone(run, 3); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(3, run.CurrentZoneIndex); Assert.AreEqual("global:aetheria.run_state.daemon-command-apply-run.zone.3.entity.1.v1", run.CurrentEntityKey); Assert.AreEqual(1, sourceZone.Entities.Count); Assert.AreEqual("Target", sourceZone.Entities[0].Name); Assert.AreEqual(2, targetZone.Entities.Count); Assert.AreEqual("Tow Station", targetZone.Entities[0].Name); Assert.AreEqual("Player", targetZone.Entities[1].Name); Assert.AreEqual(1, targetZone.Entities[1].EntityIndex); Assert.AreEqual(300, targetZone.Entities[1].PositionX, 0.0001); Assert.AreEqual(400, targetZone.Entities[1].PositionZ, 0.0001); Assert.AreEqual(1, result.Intents.Towing.Count); Assert.AreEqual("global:aetheria.run_state.daemon-command-apply-run.zone.3.entity.1.v1", result.Intents.Towing[0].ActorEntityKey); Assert.AreEqual("zone.3.entity.0", result.Intents.Towing[0].StationEntityKey); Assert.AreEqual(3, result.Intents.Towing[0].TargetZoneIndex); } [Test] public void DaemonOperationsSetsDockedCurrentShipAsDaemonRunCursor() { var run = RunWithTwoEntities(); run.Zones = new[] { run.Zones[0], new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 2, Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 0, Name = "Docking Station", DockingBayAssignments = new[] { 1 } }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 1, Name = "Docked Scout" } } } }; var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetDockedCurrentShip, "codex", "session-current", 46, ""); command.TargetEntityKey = "zone.2.entity.1"; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(2, run.CurrentZoneIndex); Assert.AreEqual("global:aetheria.run_state.daemon-command-apply-run.zone.2.entity.1.v1", run.CurrentEntityKey); } [Test] public void DaemonOperationsRejectsUndockedCurrentShipSelection() { var run = RunWithTwoEntities(); var command = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetDockedCurrentShip, "codex", "session-current", 46, ""); command.TargetEntityKey = "zone.0.entity.1"; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { command }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(0, run.CurrentZoneIndex); Assert.AreEqual("zone.0.entity.0", run.CurrentEntityKey); } [Test] public void DaemonOperationsRecordsSimulationIntentsForDaemonLoop() { var run = RunWithTwoEntities(); var move = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetMoveVector, "codex", "session-intents", 32, ""); move.DirectionX = 0.25; move.DirectionY = -0.5; move.ScalarValue = 0.75; var fire = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.FireWeaponGroup, "codex", "session-intents", 33, "zone.0.entity.0"); fire.WeaponGroup = 1; var behavior = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetBehaviorActive, "codex", "session-intents", 34, "zone.0.entity.0"); behavior.EquipmentIndex = 0; behavior.BehaviorIndex = 0; behavior.ScalarValue = 1.0; var consumable = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.ActivateConsumable, "codex", "session-intents", 35, "zone.0.entity.0"); consumable.TextValue = "repair-gel"; var ping = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SensorPing, "codex", "session-intents", 36, "zone.0.entity.0"); var result = AetheriaRuntimeDaemonOperations.Execute( run, new[] { move, fire, behavior, consumable, ping }); Assert.AreEqual(5, result.AppliedCommandIds.Count); Assert.IsTrue(result.Intents.HasAny); Assert.AreEqual("zone.0.entity.0", result.Intents.Movement.ActorEntityKey); Assert.AreEqual(0.25, result.Intents.Movement.DirectionX, 0.0001); Assert.AreEqual(-0.5, result.Intents.Movement.DirectionY, 0.0001); Assert.AreEqual(0.75, result.Intents.Movement.Magnitude, 0.0001); Assert.AreEqual(1, result.Intents.WeaponGroups.Count); Assert.IsTrue(result.Intents.WeaponGroups[0].Fire); Assert.AreEqual(1, result.Intents.WeaponGroups[0].WeaponGroup); Assert.AreEqual(1, result.Intents.Behaviors.Count); Assert.IsTrue(result.Intents.Behaviors[0].Active); Assert.AreEqual(1, result.Intents.Consumables.Count); Assert.AreEqual("repair-gel", result.Intents.Consumables[0].ItemKey); Assert.IsTrue(result.Intents.SensorPingRequested); } [Test] public void DaemonOperationsRejectsWeaponGroupIntentForMissingGroup() { var run = RunWithTwoEntities(); var negative = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.FireWeaponGroup, "codex", "session-intents", 33, "zone.0.entity.0"); negative.WeaponGroup = -1; var missing = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetWeaponGroupActive, "codex", "session-intents", 34, "zone.0.entity.0"); missing.WeaponGroup = 99; missing.ScalarValue = 1.0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { negative, missing }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(2, result.RejectedCommandIds.Count); Assert.AreEqual(0, result.Intents.WeaponGroups.Count); } [Test] public void DaemonOperationsRejectsBehaviorIntentForMissingBehavior() { var run = RunWithTwoEntities(); var negative = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetBehaviorActive, "codex", "session-intents", 34, "zone.0.entity.0"); negative.EquipmentIndex = -1; negative.BehaviorIndex = 0; negative.ScalarValue = 1.0; var missing = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.SetBehaviorActive, "codex", "session-intents", 35, "zone.0.entity.0"); missing.EquipmentIndex = 0; missing.BehaviorIndex = 99; missing.ScalarValue = 1.0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { negative, missing }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(2, result.RejectedCommandIds.Count); Assert.AreEqual(0, result.Intents.Behaviors.Count); } [Test] public void DaemonOperationsRecordsNavigationIntentsForDaemonLoop() { var run = RunWithTwoEntities(); var dock = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.Dock, "codex", "session-navigation", 37, "zone.0.entity.0"); dock.TargetEntityKey = "zone.0.entity.1"; var result = AetheriaRuntimeDaemonOperations.Execute( run, new[] { dock }); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.Intents.Docking.Count); Assert.IsTrue(result.Intents.Docking[0].Dock); Assert.AreEqual("zone.0.entity.1", result.Intents.Docking[0].TargetEntityKey); CollectionAssert.Contains(run.Zones[0].Entities[1].ChildEntityIndices, 0); CollectionAssert.Contains(run.Zones[0].Entities[1].DockingBayAssignments, 0); var undock = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.Undock, "codex", "session-navigation", 40, "zone.0.entity.0"); var undockResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { undock }); Assert.AreEqual(1, undockResult.AppliedCommandIds.Count); Assert.AreEqual(1, undockResult.Intents.Docking.Count); Assert.IsTrue(undockResult.Intents.Docking[0].Undock); Assert.AreEqual(0, run.Zones[0].Entities[1].ChildEntityIndices.Count); CollectionAssert.DoesNotContain(run.Zones[0].Entities[1].DockingBayAssignments, 0); } [Test] public void DaemonOperationsSelectsNearestDockTargetFromAuthoritativeSnapshot() { var run = RunWithTwoEntities(); var zone = run.Zones[0]; zone.Entities[0].PositionX = 0; zone.Entities[0].PositionY = 0; zone.Entities[1].PositionX = 3; zone.Entities[1].PositionY = 4; zone.Entities = zone.Entities .Concat(new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 2, Name = "Far Dock", PositionX = 8, PositionY = 0 } }) .ToArray(); var dock = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.DockNearest, "codex", "session-navigation", 37, "zone.0.entity.0"); dock.ScalarValue = 6.0; var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { dock }); Assert.AreEqual(1, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.Intents.Docking.Count); Assert.IsTrue(result.Intents.Docking[0].Dock); Assert.AreEqual("global:aetheria.run_state.daemon-command-apply-run.zone.0.entity.1.v1", result.Intents.Docking[0].TargetEntityKey); CollectionAssert.Contains(zone.Entities[1].ChildEntityIndices, 0); CollectionAssert.Contains(zone.Entities[1].DockingBayAssignments, 0); CollectionAssert.DoesNotContain(zone.Entities[2].ChildEntityIndices, 0); } [Test] public void DaemonOperationsRejectsUndockWhenEntityIsNotDocked() { var run = RunWithTwoEntities(); var undock = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.Undock, "codex", "session-navigation", 40, "zone.0.entity.0"); var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { undock }); Assert.AreEqual(0, result.AppliedCommandIds.Count); Assert.AreEqual(1, result.RejectedCommandIds.Count); Assert.AreEqual(0, result.Intents.Docking.Count); } [Test] public void DaemonOperationsRejectsDockWhenEntityIsAlreadyDocked() { var run = RunWithTwoEntities(); var dock = AetheriaRuntimeDaemonCommandDocument.Create( AetheriaRuntimeDaemonCommandKinds.Dock, "codex", "session-navigation", 37, "zone.0.entity.0"); dock.TargetEntityKey = "zone.0.entity.1"; var firstResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { dock }); var secondResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { dock }); Assert.AreEqual(1, firstResult.AppliedCommandIds.Count); Assert.AreEqual(0, secondResult.AppliedCommandIds.Count); Assert.AreEqual(1, secondResult.RejectedCommandIds.Count); Assert.AreEqual(0, secondResult.Intents.Docking.Count); CollectionAssert.Contains(run.Zones[0].Entities[1].ChildEntityIndices, 0); } [Test] public void CommandClientCanSendWithoutObservedState() { var statePath = Path.Combine( Path.GetTempPath(), "aetheria-daemon-command-client-tests", Path.GetRandomFileName(), "state.cc"); var client = new AetheriaRuntimeDaemonOperationClient(statePath, "headless-client", "session-headless"); var envelope = client.SetMoveVector(null, 0.25, -0.75, 0.5); Assert.AreEqual(AetheriaRuntimeDaemonCommandKinds.SetMoveVector, envelope.Kind); Assert.AreEqual("headless-client", envelope.ClientId); Assert.AreEqual("session-headless", envelope.SessionId); Assert.AreEqual(-1, envelope.ObservedFrameId); Assert.AreEqual("", envelope.ActorEntityKey); Assert.IsEmpty(envelope.Path); Assert.AreEqual(AetheriaRuntimeDaemonOperationIds.SetMoveVector, envelope.OperationId); Assert.IsTrue(envelope.Accepted); Assert.AreEqual(CultMeshLocalityKind.Network, envelope.Route.Kind); Assert.IsNull(envelope.Diagnostic); } [Test] public void EveCommandDocumentPreservesCultMeshInvocationAndPayload() { var request = new EveSurfaceCommandRequest( "aetheria", AetheriaRuntimePlayerSettingsCommands.SurfaceId, CultMesh.OperationInvocation( AetheriaRuntimePlayerSettingsCommands.SetPlayerName, AetheriaRuntimeEveCommandDocument.SchemaId, new CultMeshRouteHint(CultMeshLocalityKind.Ipc, "eve-ui-test"), "idempotent-player-name"), CultMesh.OperationPayload(("value", "Raven")), DateTimeOffset.UtcNow, "unity-raven"); var envelope = AetheriaRuntimeEveCommandClient.CreatePlayerSettingsCommand(request, "unity-raven"); var document = AetheriaRuntimeEveCommandClient.ToDocument(envelope); var restored = AetheriaRuntimeEveCommandClient.ToEnvelope(document); Assert.AreEqual(AetheriaRuntimePlayerSettingsCommands.SetPlayerName, document.OperationId); Assert.AreEqual(AetheriaRuntimeEveCommandDocument.SchemaId, document.OperationSchemaId); Assert.AreEqual(CultMeshLocalityKind.Ipc.ToString(), document.OperationRouteKind); Assert.AreEqual("eve-ui-test", document.OperationRouteDescription); Assert.AreEqual("idempotent-player-name", document.OperationIdempotencyKey); Assert.AreEqual(AetheriaRuntimePlayerSettingsCommands.SetPlayerName, document.Operation.OperationId); Assert.AreEqual(AetheriaRuntimeEveCommandDocument.SchemaId, document.Operation.SchemaId); Assert.AreEqual(CultMeshLocalityKind.Ipc.ToString(), document.Operation.RouteKind); Assert.AreEqual("eve-ui-test", document.Operation.RouteDescription); Assert.AreEqual("idempotent-player-name", document.Operation.IdempotencyKey); Assert.IsTrue(document.Payload.TryGetValue("value", out var documentValue)); Assert.AreEqual("Raven", documentValue); Assert.AreEqual(AetheriaRuntimePlayerSettingsCommands.SetPlayerName, restored.Invocation.OperationId); Assert.AreEqual(CultMeshLocalityKind.Ipc, restored.Invocation.RouteHint.Kind); Assert.AreEqual("Raven", restored.Payload.GetString("value")); Assert.AreEqual("Raven", restored.PlayerSettings.PlayerName); } private static AetheriaRuntimeRunCheckpointCommit RunWithTwoEntities() { return new AetheriaRuntimeRunCheckpointCommit { RunId = "daemon-command-apply-run", CurrentZoneIndex = 0, CurrentEntityKey = "zone.0.entity.0", Credits = 1000, Zones = new[] { new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0, Entities = new[] { new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 0, Name = "Player", TargetEntityIndex = -1, ShutdownPerformance = 0.25, Contacts = new[] { new AetheriaRuntimeEntityContactCommit { TargetEntityIndex = 1, Visible = true, Hostile = true } }, Equipment = new[] { new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "reactor", Enabled = true } }, new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "laser", Enabled = true } } }, WeaponGroups = new[] { new[] { 0 }, new[] { 1 }, Array.Empty() }, BehaviorStates = new[] { new AetheriaRuntimeBehaviorStateCommit { OwnerKind = "equipment", OwnerIndex = 0, BehaviorIndex = 0, BehaviorKind = "Thermotoggle", ThermotoggleTargetTemperature = 300.0 }, new AetheriaRuntimeBehaviorStateCommit { OwnerKind = "equipment", OwnerIndex = 1, BehaviorIndex = 0, BehaviorKind = "Shield" } }, CargoContents = new[] { new AetheriaRuntimeCargoBayLoadoutCommit { Items = new[] { new AetheriaRuntimeLoadoutItemSlotCommit { X = 2, Y = 3, Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "ore", Quantity = 12 } } } } }, StatGrids = new[] { new AetheriaRuntimeEntityStatGridCommit { Name = "hull_conductivity_x", Width = 2, Height = 2, Values = new[] { 1.0, 0.0, 0.0, 1.0 } }, new AetheriaRuntimeEntityStatGridCommit { Name = "hull_conductivity_y", Width = 2, Height = 2, Values = new[] { 0.0, 1.0, 1.0, 0.0 } } } }, new AetheriaRuntimeEntitySnapshotCommit { EntityIndex = 1, Name = "Target", TargetEntityIndex = -1, CargoContents = new[] { new AetheriaRuntimeCargoBayLoadoutCommit() } } }, DroppedPickups = new[] { new AetheriaRuntimeDroppedPickupCommit { PickupIndex = 0, PositionX = 10, PositionY = 11, PositionZ = 12, Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "loot-cell", Quantity = 1 } } } } } }; } private static AetheriaRuntimeZoneSnapshotCommit FindZone(AetheriaRuntimeRunCheckpointCommit run, int zoneIndex) { foreach (var zone in run.Zones) { if (zone.ZoneIndex == zoneIndex) return zone; } Assert.Fail("Expected zone " + zoneIndex); return null; } private static AetheriaRuntimeObservedDaemonState ObservedState(long frameId, long soaGeneration) { var frame = AetheriaRuntimeDaemonFrameDocument.Create( new AetheriaRuntimeRunCheckpointCommit { RunId = "cursor-run" }, "daemon", "session", frameId, 0, 0.02); var soaView = AetheriaRuntimeDaemonSoaViewDocument.Create( "daemon", "session", frameId, soaGeneration, new[] { new AetheriaRuntimeDaemonSoaBufferDocument { BufferId = "hot" } }, new[] { new AetheriaRuntimeDaemonSoaColumnDocument { ColumnId = "position", BufferId = "hot" } }); return new AetheriaRuntimeObservedDaemonState( frame, soaView, "state.cc.daemon.frame.cc", "state.cc.daemon.soa.cc"); } private static void PublishLatestFrameThroughVerseClient( string statePath, AetheriaRuntimeDaemonFrameDocument frame) { using var client = AetheriaRuntimeVerseClient .OpenAsync(statePath, "daemon-surface-command-test", startServer: false, pullOnOpen: true) .GetAwaiter() .GetResult(); client.LatestFrame() .ReplaceAsync(frame) .GetAwaiter() .GetResult(); client.FlushAsync() .GetAwaiter() .GetResult(); } private static AetheriaRuntimeCatalogItem CatalogItem( string itemKey, IReadOnlyList behaviorPayloads) { return new AetheriaRuntimeCatalogItem( itemKey, itemKey, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0, Array.Empty(), 0, 0, 0, Array.Empty(), Array.Empty(), behaviorPayloads, "", "", behaviorPayloads.Select(payload => payload.Kind).ToArray(), 1, false, 0, 1, "", "", "", "", "", 0, 0, Array.Empty(), "", 1, 0, 0, 0, false, 0, 0, "", Array.Empty(), Array.Empty(), "", ""); } private static AetheriaRuntimeBehaviorValue NumberValue(double value) { return new AetheriaRuntimeBehaviorValue( "", "", value, false, "", "", Array.Empty(), Array.Empty()); } private static AetheriaRuntimeBehaviorValue EmptyBehaviorValue(string kind) { return new AetheriaRuntimeBehaviorValue( kind, "", 0, false, "", "", Array.Empty(), Array.Empty()); } private static bool ContainsSurfaceMetric( AetheriaRuntimeSurfaceComponent component, string label, string value) { if (component.Kind == "metric" && component.Props.TryGetValue("label", out var actualLabel) && component.Props.TryGetValue("value", out var actualValue) && actualLabel == label && actualValue == value) { return true; } return component.Children.Any(child => ContainsSurfaceMetric(child, label, value)); } private static bool ContainsSurfaceProp( AetheriaRuntimeSurfaceComponent component, string key, string value) { if (component.Props.TryGetValue(key, out var actual) && string.Equals(actual, value, StringComparison.Ordinal)) { return true; } return component.Children.Any(child => ContainsSurfaceProp(child, key, value)); } private static bool ContainsSurfaceStateBinding( AetheriaRuntimeSurfaceComponent component, string targetProp, string sourceId, string schemaId) { if (component.StateBindings.Any(binding => binding.TargetProp == targetProp && binding.SourceId == sourceId && binding.SchemaId == schemaId)) { return true; } return component.Children.Any(child => ContainsSurfaceStateBinding(child, targetProp, sourceId, schemaId)); } private static bool ContainsEveSurfaceMetric( EveSurfaceComponent component, string label, string value) { if (component.Kind == "metric" && component.Props.TryGetValue("label", out var actualLabel) && component.Props.TryGetValue("value", out var actualValue) && actualLabel == label && actualValue == value) { return true; } return component.Children.Any(child => ContainsEveSurfaceMetric(child, label, value)); } private static bool ContainsEveSurfaceProp( EveSurfaceComponent component, string key, string value) { if (component.Props.TryGetValue(key, out var actual) && string.Equals(actual, value, StringComparison.Ordinal)) { return true; } return component.Children.Any(child => ContainsEveSurfaceProp(child, key, value)); } private static bool ContainsEveSurfaceStateBinding( EveSurfaceComponent component, string targetProp, string sourceId, string schemaId) { if (component.StateBindings.Any(binding => binding.TargetProp == targetProp && binding.SourceId == sourceId && binding.SchemaId == schemaId)) { return true; } return component.Children.Any(child => ContainsEveSurfaceStateBinding(child, targetProp, sourceId, schemaId)); } }