3856 lines
154 KiB
C#
3856 lines
154 KiB
C#
using GameCult.Aetheria.State.Verse;
|
|
using GameCult.Eve.Surface;
|
|
using NUnit.Framework;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
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 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(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));
|
|
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<string, string>(StringComparer.Ordinal)
|
|
{
|
|
["label"] = "Target",
|
|
["value"] = "stale",
|
|
[AetheriaRuntimeSurfaceStateRefs.Source] = AetheriaRuntimeDaemonStateRefs.CurrentTargetName
|
|
},
|
|
Array.Empty<EveSurfaceComponent>()),
|
|
Array.Empty<EveStyleToken>()),
|
|
Array.Empty<EveCommandTemplate>());
|
|
|
|
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<string, string>(StringComparer.Ordinal)
|
|
{
|
|
["label"] = "Heat",
|
|
["description"] = "stale",
|
|
["descriptionRef"] = AetheriaRuntimeDaemonStateRefs.CurrentTargetName,
|
|
[AetheriaRuntimeSurfaceStateRefs.Value] = AetheriaRuntimeDaemonStateRefs.CurrentTargetName
|
|
},
|
|
Array.Empty<EveSurfaceComponent>()),
|
|
Array.Empty<EveStyleToken>()),
|
|
Array.Empty<EveCommandTemplate>());
|
|
|
|
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<AetheriaRuntimeBehaviorMapEntry>());
|
|
var catalog = new AetheriaRuntimeCatalogSnapshot(
|
|
new[]
|
|
{
|
|
CatalogItem(
|
|
"test-laser",
|
|
new[]
|
|
{
|
|
new AetheriaRuntimeBehaviorPayload(
|
|
0,
|
|
"Weapon",
|
|
2,
|
|
new[] { new AetheriaRuntimeBehaviorField(7, statValue) })
|
|
})
|
|
},
|
|
Array.Empty<AetheriaRuntimeCorporation>(),
|
|
Array.Empty<AetheriaRuntimeNameFile>());
|
|
|
|
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 positionX = new AetheriaRuntimeDaemonSoaColumnDocument
|
|
{
|
|
ColumnId = "position-x",
|
|
Kind = AetheriaRuntimeDaemonSoaColumnKinds.PositionX,
|
|
BufferId = buffer.BufferId,
|
|
ScalarType = "float32",
|
|
ByteOffset = 0,
|
|
ElementStride = 4,
|
|
ElementCount = 128,
|
|
Unit = "world_units",
|
|
CoordinateSpace = "zone"
|
|
};
|
|
var dirtyRange = new AetheriaRuntimeDaemonSoaDirtyRangeDocument
|
|
{
|
|
ColumnId = positionX.ColumnId,
|
|
StartIndex = 16,
|
|
Count = 8,
|
|
Generation = 77
|
|
};
|
|
|
|
var view = AetheriaRuntimeDaemonSoaViewDocument.Create(
|
|
"ymir-daemon",
|
|
"session-soa",
|
|
42,
|
|
77,
|
|
new[] { buffer },
|
|
new[] { positionX },
|
|
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.PositionX, 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-x",
|
|
Kind = AetheriaRuntimeDaemonSoaColumnKinds.PositionX,
|
|
BufferId = "transform-hot",
|
|
ScalarType = "float32",
|
|
ByteOffset = 16,
|
|
ElementStride = 4,
|
|
ElementCount = 64,
|
|
Unit = "world_units",
|
|
CoordinateSpace = "zone"
|
|
}
|
|
},
|
|
new[]
|
|
{
|
|
new AetheriaRuntimeDaemonSoaDirtyRangeDocument
|
|
{
|
|
ColumnId = "position-x",
|
|
StartIndex = 8,
|
|
Count = 4,
|
|
Generation = 91
|
|
}
|
|
},
|
|
AetheriaRuntimeDaemonSoaBackends.MemoryMappedFile);
|
|
|
|
var index = AetheriaRuntimeDaemonSoaViewIndex.Build(view);
|
|
|
|
Assert.IsTrue(index.IsValid);
|
|
Assert.IsTrue(index.TryGetFirstColumnOfKind(AetheriaRuntimeDaemonSoaColumnKinds.PositionX, out var binding));
|
|
Assert.AreEqual("position-x", binding.Column.ColumnId);
|
|
Assert.AreEqual("transform-hot", binding.Buffer.BufferId);
|
|
Assert.AreEqual(144, binding.AbsoluteByteOffset);
|
|
Assert.AreEqual(256, binding.ByteLength);
|
|
Assert.IsTrue(binding.DirectMemoryCompatible);
|
|
Assert.AreEqual(1, index.GetDirtyRanges("position-x").Count);
|
|
Assert.AreEqual(8, index.GetDirtyRanges("position-x")[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<AetheriaRuntimeDaemonRenderGroupDocument>();
|
|
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<AetheriaRuntimeGravityInfluenceBrush>();
|
|
var count = AetheriaRuntimeDaemonRenderQueries.QueryGravityInfluences(
|
|
zone,
|
|
new AetheriaRuntimeXzRect(-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<AetheriaRuntimeDaemonBodyView>();
|
|
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);
|
|
}
|
|
|
|
[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<AetheriaRuntimeDaemonCompassMarker>();
|
|
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<int>();
|
|
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 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<AetheriaRuntimeDaemonWormholeExit>();
|
|
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<AetheriaRuntimeDaemonSoaBufferDocument>(),
|
|
Array.Empty<AetheriaRuntimeDaemonSoaColumnDocument>(),
|
|
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 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-x",
|
|
Kind = AetheriaRuntimeDaemonSoaColumnKinds.PositionX,
|
|
BufferId = "entity-hot",
|
|
ScalarType = "float32",
|
|
ElementStride = 4,
|
|
ElementCount = 64
|
|
}
|
|
});
|
|
|
|
AetheriaRuntimeDaemonFrameStore.PublishFrame(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);
|
|
AetheriaRuntimeDaemonFrameStore.PublishFrame(statePath, frame);
|
|
var request = new EveSurfaceCommandRequest(
|
|
"aetheria.daemon",
|
|
AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId,
|
|
"aetheria.daemon.commands.FireWeaponGroup",
|
|
new Dictionary<string, string>(StringComparer.Ordinal),
|
|
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);
|
|
AetheriaRuntimeDaemonFrameStore.PublishFrame(statePath, frame);
|
|
var request = new EveSurfaceCommandRequest(
|
|
"aetheria.daemon",
|
|
AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId,
|
|
"aetheria.daemon.commands.SensorPing",
|
|
new Dictionary<string, string>(StringComparer.Ordinal),
|
|
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,
|
|
"aetheria.daemon.commands.TransferCargoItem",
|
|
new Dictionary<string, string>(StringComparer.Ordinal),
|
|
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<AetheriaRuntimeEntityContactCommit>();
|
|
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 DaemonOperationsOwnsActionBarBindingsInDaemonState()
|
|
{
|
|
var run = RunWithTwoEntities();
|
|
run.ActionBarBindings = new[]
|
|
{
|
|
new AetheriaRuntimeActionBarBindingCommit
|
|
{
|
|
ControlPath = "<Keyboard>/1",
|
|
Kind = "equipment",
|
|
EquipmentIndex = 0
|
|
}
|
|
};
|
|
var set = AetheriaRuntimeDaemonCommandDocument.Create(
|
|
AetheriaRuntimeDaemonCommandKinds.SetActionBarBinding,
|
|
"codex",
|
|
"session-bindings",
|
|
17,
|
|
"zone.0.entity.0");
|
|
set.TextValue = "<Keyboard>/1";
|
|
set.ActionBarBinding.Kind = "weapon_group";
|
|
set.ActionBarBinding.ItemKey = "laser";
|
|
set.WeaponGroup = 2;
|
|
var clear = AetheriaRuntimeDaemonCommandDocument.Create(
|
|
AetheriaRuntimeDaemonCommandKinds.ClearActionBarBinding,
|
|
"codex",
|
|
"session-bindings",
|
|
18,
|
|
"zone.0.entity.0");
|
|
clear.TextValue = "<Keyboard>/1";
|
|
|
|
var setResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { set });
|
|
|
|
Assert.AreEqual(1, setResult.AppliedCommandIds.Count);
|
|
Assert.AreEqual(1, run.ActionBarBindings.Count);
|
|
Assert.AreEqual("weapon_group", run.ActionBarBindings[0].Kind);
|
|
Assert.AreEqual("laser", run.ActionBarBindings[0].ItemKey);
|
|
Assert.AreEqual(2, run.ActionBarBindings[0].WeaponGroup);
|
|
|
|
var clearResult = AetheriaRuntimeDaemonOperations.Execute(run, new[] { clear });
|
|
|
|
Assert.AreEqual(1, clearResult.AppliedCommandIds.Count);
|
|
Assert.AreEqual(0, run.ActionBarBindings.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void DaemonOperationsRejectsWeaponGroupActionBarBindingForMissingGroup()
|
|
{
|
|
var run = RunWithTwoEntities();
|
|
var negative = AetheriaRuntimeDaemonCommandDocument.Create(
|
|
AetheriaRuntimeDaemonCommandKinds.SetActionBarBinding,
|
|
"codex",
|
|
"session-bindings",
|
|
17,
|
|
"zone.0.entity.0");
|
|
negative.TextValue = "<Keyboard>/1";
|
|
negative.ActionBarBinding.Kind = "weapon_group";
|
|
negative.WeaponGroup = -1;
|
|
var tooHigh = AetheriaRuntimeDaemonCommandDocument.Create(
|
|
AetheriaRuntimeDaemonCommandKinds.SetActionBarBinding,
|
|
"codex",
|
|
"session-bindings",
|
|
18,
|
|
"zone.0.entity.0");
|
|
tooHigh.TextValue = "<Keyboard>/2";
|
|
tooHigh.ActionBarBinding.Kind = "weapon_group";
|
|
tooHigh.WeaponGroup = 99;
|
|
|
|
var result = AetheriaRuntimeDaemonOperations.Execute(run, new[] { negative, tooHigh });
|
|
|
|
Assert.AreEqual(0, result.AppliedCommandIds.Count);
|
|
Assert.AreEqual(2, result.RejectedCommandIds.Count);
|
|
Assert.AreEqual(0, run.ActionBarBindings.Count);
|
|
}
|
|
|
|
[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<AetheriaRuntimeBehaviorStateCommit>();
|
|
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<AetheriaRuntimeLoadoutTemplateCommit>()
|
|
});
|
|
|
|
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"
|
|
}
|
|
}
|
|
}
|
|
};
|
|
var command = AetheriaRuntimeDaemonCommandDocument.Create(
|
|
AetheriaRuntimeDaemonCommandKinds.TowToStation,
|
|
"codex",
|
|
"session-towing",
|
|
46,
|
|
"zone.0.entity.0");
|
|
command.TargetEntityKey = "zone.3.entity.0";
|
|
command.TargetZoneIndex = 3;
|
|
command.PositionX = 300;
|
|
command.PositionY = 400;
|
|
|
|
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);
|
|
}
|
|
|
|
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<int>()
|
|
},
|
|
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-x", BufferId = "hot" } });
|
|
|
|
return new AetheriaRuntimeObservedDaemonState(
|
|
frame,
|
|
soaView,
|
|
"state.cc.daemon.frame.cc",
|
|
"state.cc.daemon.soa.cc");
|
|
}
|
|
|
|
private static AetheriaRuntimeCatalogItem CatalogItem(
|
|
string itemKey,
|
|
IReadOnlyList<AetheriaRuntimeBehaviorPayload> behaviorPayloads)
|
|
{
|
|
return new AetheriaRuntimeCatalogItem(
|
|
itemKey,
|
|
itemKey,
|
|
"",
|
|
"",
|
|
"",
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
Array.Empty<AetheriaRuntimeShapeCell>(),
|
|
0,
|
|
0,
|
|
0,
|
|
Array.Empty<AetheriaRuntimeShapeCell>(),
|
|
Array.Empty<AetheriaRuntimeHardpoint>(),
|
|
behaviorPayloads,
|
|
"",
|
|
"",
|
|
behaviorPayloads.Select(payload => payload.Kind).ToArray(),
|
|
1,
|
|
false,
|
|
0,
|
|
1,
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
"",
|
|
0,
|
|
0,
|
|
Array.Empty<AetheriaRuntimeCurveKey>(),
|
|
"",
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
false,
|
|
0,
|
|
0,
|
|
"",
|
|
Array.Empty<AetheriaRuntimeAudioStat>(),
|
|
Array.Empty<AetheriaRuntimeCurveKey>(),
|
|
"",
|
|
"");
|
|
}
|
|
|
|
private static AetheriaRuntimeBehaviorValue NumberValue(double value)
|
|
{
|
|
return new AetheriaRuntimeBehaviorValue(
|
|
"",
|
|
"",
|
|
value,
|
|
false,
|
|
"",
|
|
"",
|
|
Array.Empty<AetheriaRuntimeBehaviorValue>(),
|
|
Array.Empty<AetheriaRuntimeBehaviorMapEntry>());
|
|
}
|
|
|
|
private static AetheriaRuntimeBehaviorValue EmptyBehaviorValue(string kind)
|
|
{
|
|
return new AetheriaRuntimeBehaviorValue(
|
|
kind,
|
|
"",
|
|
0,
|
|
false,
|
|
"",
|
|
"",
|
|
Array.Empty<AetheriaRuntimeBehaviorValue>(),
|
|
Array.Empty<AetheriaRuntimeBehaviorMapEntry>());
|
|
}
|
|
|
|
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 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));
|
|
}
|
|
}
|