2026-07-15 08:27:36 +01:00
using Aetheria.State ;
2026-07-11 17:43:48 +01:00
using Aetheria.State.Daemon ;
2026-07-15 08:27:36 +01:00
using Aetheria.State.Documents ;
2026-07-09 19:46:41 +01:00
using GameCult.Aetheria.State.Verse ;
2026-07-15 04:04:05 +01:00
using GameCult.Caching ;
2026-07-15 22:59:51 +01:00
using GameCult.Eve.PluginFields ;
2026-07-17 01:45:33 +01:00
using GameCult.Eve.Surface ;
using GameCult.Mesh ;
2026-07-11 19:14:38 +01:00
using System.Globalization ;
2026-07-09 19:46:41 +01:00
2026-07-11 17:43:48 +01:00
var checks = new AetheriaDaemonYmirSmokeChecks ( ) ;
2026-07-14 16:14:59 +01:00
if ( args . Contains ( "--gravity" , StringComparer . Ordinal ) )
{
checks . RunGravity ( ) ;
Console . WriteLine ( "Daemon Ymir gravity-sign smoke passed." ) ;
}
else if ( args . Contains ( "--loadout" , StringComparer . Ordinal ) )
2026-07-13 16:53:25 +01:00
{
checks . RunLoadout ( ) ;
Console . WriteLine ( "Daemon loadout hardpoint smoke passed." ) ;
}
2026-07-14 01:03:34 +01:00
else if ( args . Contains ( "--pickup" , StringComparer . Ordinal ) )
{
checks . RunPickup ( ) ;
Console . WriteLine ( "Daemon Ymir pickup-contact smoke passed." ) ;
}
2026-07-14 22:25:05 +01:00
else if ( args . Contains ( "--payload" , StringComparer . Ordinal ) )
{
checks . RunPayload ( ) ;
Console . WriteLine ( "Daemon retained Ymir payload smoke passed." ) ;
}
2026-07-13 16:53:25 +01:00
else
{
checks . Run ( ) ;
Console . WriteLine ( "Daemon Ymir physical payload smoke passed." ) ;
}
2026-07-09 19:46:41 +01:00
2026-07-11 17:43:48 +01:00
internal sealed class AetheriaDaemonYmirSmokeChecks
2026-07-09 19:46:41 +01:00
{
2026-07-15 03:52:56 +01:00
private static readonly List < AetheriaYmirWorldPhysics > OwnedPhysics = [ ] ;
public void RunGravity ( ) = > RunCheck ( PositiveGravityDepthAttractsAndProjectsAsAWell ) ;
2026-07-14 16:14:59 +01:00
2026-07-13 16:53:25 +01:00
public void RunLoadout ( ) = > DaemonLoadoutsRespectFactionAvailabilityAndHullRoles ( ) ;
2026-07-14 01:03:34 +01:00
public void RunPickup ( )
{
2026-07-15 03:52:56 +01:00
RunCheck ( RetainedWorldAdvancesEveryFixedSubstep ) ;
RunCheck ( StableEntityIdentitySurvivesCrossZoneReindex ) ;
2026-07-15 05:30:06 +01:00
RunCheck ( TractorRampsAndPullsThroughYmirWithoutTeleportingCargo ) ;
2026-07-15 03:52:56 +01:00
RunCheck ( PickupIsCapacityCheckedExactlyOnceAndExpires ) ;
2026-07-15 16:36:13 +01:00
RunCheck ( StationBodiesCannotConsumePickups ) ;
2026-07-15 03:52:56 +01:00
RunCheck ( PickupShieldContactCollectsOrBounces ) ;
2026-07-15 08:27:36 +01:00
RunCheck ( YmirRestartDoesNotReplayConsumedPickupContact ) ;
2026-07-14 01:03:34 +01:00
}
2026-07-14 22:25:05 +01:00
public void RunPayload ( )
{
2026-07-15 03:52:56 +01:00
RunCheck ( YmirMovesProjectileAndReportsStableContact ) ;
RunCheck ( PayloadQueryExcludesItsSource ) ;
RunCheck ( PayloadBodiesDoNotCollideWithEachOther ) ;
RunCheck ( OverlappingMineRemainsQueryableAfterArming ) ;
2026-07-14 22:25:05 +01:00
}
2026-07-14 21:38:46 +01:00
private static void RetainedWorldAdvancesEveryFixedSubstep ( )
{
var ship = Entity ( 0 , 0 , "player" ) ;
ship . VelocityX = 10 ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "retained-substep-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship ] } ]
} ;
2026-07-15 03:52:56 +01:00
using var physics = NewPhysics ( ) ;
2026-07-14 21:38:46 +01:00
AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-retained-substeps.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = physics ,
FrameId = 1 ,
FixedDeltaSeconds = 0.1 ,
SimulationStepCount = 3 ,
SimulationTimeSeconds = 0.3 ,
BuildPublications = false
} ) ;
RequireNear ( 3 , ship . PositionX , 0.05 ,
"one retained Box3D world must advance once for every fixed substep, not once per publication frame" ) ;
}
private static void StableEntityIdentitySurvivesCrossZoneReindex ( )
{
var departing = Entity ( 0 , 0 , "player" ) ;
departing . EntityId = "cross-zone.departing" ;
var survivor = Entity ( 1 , 100 , "player" ) ;
survivor . EntityId = "cross-zone.survivor" ;
var source = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ departing , survivor ]
} ;
var destination = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 1 , Entities = [ ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "cross-zone-retained-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ source , destination ]
} ;
2026-07-15 03:52:56 +01:00
using var physics = NewPhysics ( ) ;
2026-07-14 21:38:46 +01:00
AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-cross-zone-before.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = physics ,
FrameId = 1 ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = 0.1 ,
BuildPublications = false
} ) ;
survivor . EntityIndex = 0 ;
departing . EntityIndex = 0 ;
departing . PositionX = 250 ;
source . Entities = [ survivor ] ;
destination . Entities = [ departing ] ;
run . CurrentZoneIndex = 1 ;
run . CurrentEntityKey = "zone.1.entity.0" ;
AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-cross-zone-after.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = physics ,
FrameId = 2 ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = 0.2 ,
BuildPublications = false
} ) ;
RequireNear ( 100 , survivor . PositionX , 0.05 ,
"source-zone reindex must not give a survivor the departed entity's retained Box3D body" ) ;
RequireNear ( 250 , departing . PositionX , 0.05 ,
"a cross-zone arrival must retain its stable identity while spawning in the destination session" ) ;
}
2026-07-09 19:46:41 +01:00
public void Run ( )
{
2026-07-15 03:52:56 +01:00
Action [ ] checks =
[
PositiveGravityDepthAttractsAndProjectsAsAWell ,
2026-07-15 20:17:05 +01:00
VolumeSurfaceKeepsNativeShaderAbiInAssetVariant ,
2026-07-15 03:52:56 +01:00
YmirMovesProjectileAndReportsStableContact ,
InstantWeaponRequestSurvivesLockAcquisition ,
2026-07-17 04:20:16 +01:00
GuidedWeaponPublishesPresentationProfileWithoutPhysicalAuthority ,
2026-07-16 22:32:40 +01:00
CombatLockSurvivesPublicFrameRestart ,
2026-07-15 03:52:56 +01:00
ConstantWeaponRunsOnDaemonThroughYmirBeamContact ,
ChargedWeaponCannotBypassChargeLifecycle ,
ChargedWeaponHoldRiskMalfunctionsDeterministically ,
DeployableWeaponRunsThroughYmirAndDetonatesOnDaemon ,
DeployableRangeExpiryDetonatesAfterYmirMovement ,
CanonicalCatalogPublishesRecoveredMineLauncher ,
EnergyFundedShieldInterceptsDamageBeforeHull ,
ArmorCellsResolveBeforeEquipmentAndHull ,
2026-07-17 04:27:37 +01:00
ShipSchematicProjectsDaemonTopologyAndEquipmentState ,
2026-07-16 21:14:03 +01:00
EquipmentDestructionDisablesBehaviorAndCockpitKillsBeforeHull ,
2026-07-15 03:52:56 +01:00
DestructionDropsLootExactlyOnce ,
DaemonSimulationTreatsYmirHitAsPresentationOnly ,
ProjectileContactCannotKill ,
MissingWorldPhysicsOwnerCannotAdvanceShips ,
2026-07-17 00:17:12 +01:00
DockingUsesRealBaysAndFossilUndockRules ,
2026-07-17 04:00:20 +01:00
DockedEntitiesCannotAttackOrBeTargeted ,
2026-07-17 00:46:58 +01:00
RefitIsAtomicAndUsesTypedPlacement ,
2026-07-17 00:56:01 +01:00
CargoTransferUsesSpatialAtomicTransaction ,
2026-07-17 01:45:33 +01:00
DockedRefitSurfacePublishesGenericCommands ,
2026-07-17 01:52:36 +01:00
FossilVelocityBehaviorsRunInDaemonFlightStep ,
2026-07-17 02:55:07 +01:00
BehaviorChainsGateAuthoritativeStatModifiers ,
2026-07-17 03:03:30 +01:00
ResourceBehaviorsStopEquipmentChainsInAuthoredOrder ,
2026-07-17 03:08:56 +01:00
ThermotoggleSeedsAndGatesFromDaemonOwnedTarget ,
2026-07-17 03:37:49 +01:00
InputCapabilityPublishesExactBehaviorLevers ,
2026-07-17 04:37:35 +01:00
InputCapabilityPublishesConsumableActionBarState ,
2026-07-17 03:46:33 +01:00
InputCapabilityPublishesHeldWeaponGroupLever ,
2026-07-17 04:42:42 +01:00
InputCapabilityPublishesNativeTargetAndInteractControls ,
2026-07-17 02:02:10 +01:00
ReflectorUsesSharedStellarLightFieldWithoutAccumulating ,
2026-07-17 02:28:38 +01:00
SensorPingIsActorScopedEnergyGatedAndReconnectable ,
2026-07-17 02:40:34 +01:00
TurretControllerAcquiresAimsAndTriggersExactWeapons ,
2026-07-15 03:52:56 +01:00
TractorRampsAndPullsThroughYmirWithoutTeleportingCargo ,
PickupIsCapacityCheckedExactlyOnceAndExpires ,
2026-07-15 20:46:05 +01:00
TradePurchaseDerivesAcceptanceFromDaemonState ,
2026-07-17 01:06:25 +01:00
TradeSaleIsDaemonPricedSpatialAndAtomic ,
2026-07-15 16:36:13 +01:00
StationBodiesCannotConsumePickups ,
2026-07-15 03:52:56 +01:00
PickupShieldContactCollectsOrBounces ,
2026-07-17 05:53:02 +01:00
CultCacheRestartPreservesLoadoutAndBehaviorState ,
2026-07-15 08:27:36 +01:00
YmirRestartDoesNotReplayConsumedPickupContact ,
2026-07-15 03:52:56 +01:00
ThermalCellsUseFossilConductionAndRadiation ,
EnergyNetworkSettlesReactorAfterConsumers ,
RadiatorPumpsHeatBeforeReactorSettlement ,
EquipmentThermalPerformanceOwnsShutdownAndWear ,
ThermalTopologyComesFromHullAndEquipment ,
ThermalMedicalExposureUsesCockpitTemperature ,
ThermalMedicalDeathUsesOrdinaryDestructionPath ,
MultipleActorsUseTheSameMovementLever ,
2026-07-16 15:47:38 +01:00
DirectionalThrustersOwnOrdinaryFlightFeedback ,
UnpoweredThrustersCannotMoveOrAdvertisePlume ,
2026-07-17 03:25:16 +01:00
SpecializedBehaviorSuccessGatesTrailingWear ,
2026-07-16 15:47:38 +01:00
RareAetherDriveSpoolsOnlyOnModifiedHullFixture ,
2026-07-15 06:10:08 +01:00
LookDirectionRejectsInvalidVectorsWithoutMutatingTheShip ,
2026-07-15 03:52:56 +01:00
AgentClaimsAndCompletesExploreTaskThroughCommands ,
2026-07-17 06:21:10 +01:00
AgentTaskSurvivesCultCacheRestart ,
2026-07-15 03:52:56 +01:00
SchedulerAssignsHighestPriorityCompatibleTask ,
SchedulerRequeuesTaskFromDeadAgent ,
SchedulerCollapsesDuplicateAssignmentMarkers ,
2026-07-17 05:46:01 +01:00
CancellingAgentTaskReleasesSchedulerControls ,
2026-07-15 03:52:56 +01:00
SchedulerAssignsShortestGalaxyRoute ,
2026-07-16 23:30:19 +01:00
WormholeTraversalUsesPersistedEnterTransferExitPhases ,
2026-07-15 03:52:56 +01:00
AgentTraversesGalaxyRouteBeforeExecutingTask ,
IdleAgentReturnsToCanonicalHomeAndDocks ,
ControlledShipDoesNotReceiveAutonomousHelmCommands ,
AttackAgentControlsOptimumRangeThroughMovementLever ,
AttackTaskAdmissionRejectsImpossibleWork ,
AgentCompletesAttackTaskThroughTargetFireAndYmir ,
AgentCompletesHaulTaskThroughMovementAndCargoCommands ,
RejectedHaulTransferDoesNotAdvanceTask ,
AgentPatrolsHistoricalOrbitCircuitThroughMovementCommands ,
TickReconcilesAndEvaluatesCatalogBehaviors ,
DaemonLoadoutsRespectFactionAvailabilityAndHullRoles ,
AgentMinesAsteroidThroughEquippedBehavior ,
CargoCapacityComesFromHullAndCatalogVolumes ,
AgentSurveysBodyIntoCorporationKnowledge ,
AgentTowsStationIntoPersistentOrbit
] ;
foreach ( var check in checks )
RunCheck ( check ) ;
}
2026-07-17 02:55:07 +01:00
private static void BehaviorChainsGateAuthoritativeStatModifiers ( )
{
var thruster = CatalogItem ( "modifier-target" , new AetheriaRuntimeBehaviorPayload (
0 , "Thruster" , 0 ,
[new AetheriaRuntimeBehaviorField(1, PerformanceStat(10))] ) ) ;
var controls = CatalogItem ( "modifier-controls" ,
new AetheriaRuntimeBehaviorPayload ( 0 , "Switch" , 0 , [ ] ) ,
new AetheriaRuntimeBehaviorPayload ( 1 , "StatModifier" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , StatReference ( "ThrusterData" , "Thrust" ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , StringValue ( "Multiplier" ) )
] ) ,
new AetheriaRuntimeBehaviorPayload ( 2 , "Trigger" , 1 , [ ] ) ,
new AetheriaRuntimeBehaviorPayload ( 3 , "StatModifier" , 1 ,
[
new AetheriaRuntimeBehaviorField ( 1 , StatReference ( "Thruster" , "Thrust" ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 5 ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , StringValue ( "Constant" ) )
] ) ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ thruster , controls ] , [ ] , [ ] ) ;
var entity = Entity ( 0 , 0 , "player" ) ;
entity . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = thruster . ItemKey , Enabled = true , Durability = 1 , Quality = 1 } } ,
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = controls . ItemKey , Enabled = true , Durability = 1 , Quality = 1 } }
] ;
var activate = new [ ]
{
new AetheriaRuntimeDaemonBehaviorIntent
{ ActorEntityKey = "zone.0.entity.0" , EquipmentIndex = 1 , BehaviorIndex = 0 , Active = true } ,
new AetheriaRuntimeDaemonBehaviorIntent
{ ActorEntityKey = "zone.0.entity.0" , EquipmentIndex = 1 , BehaviorIndex = 2 , Active = true }
} ;
2026-07-17 03:03:30 +01:00
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] ,
2026-07-17 02:55:07 +01:00
[ new AetheriaRuntimeDaemonBehaviorIntent
{ ActorEntityKey = "zone.1.entity.0" , EquipmentIndex = 1 , BehaviorIndex = 0 , Active = true } ] ,
2026-07-17 03:03:30 +01:00
catalog , 0.1 ) ;
2026-07-17 02:55:07 +01:00
var target = AetheriaRuntimeEquippedBehaviorQueries . FindOperational ( entity , catalog , "Thruster" ) . Single ( ) ;
RequireNear ( 10 , target . EvaluateStat ( 1 ) , 0.000001 ,
"a behavior command for the same entity index in another zone must not cross-activate this ship" ) ;
2026-07-17 03:03:30 +01:00
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , activate , catalog , 0.1 ) ;
2026-07-17 02:55:07 +01:00
RequireNear ( 25 , target . EvaluateStat ( 1 ) , 0.000001 ,
"switch and one-shot trigger groups must multiply then add through the shared daemon stat path" ) ;
var modifierStates = entity . BehaviorStates . Where ( value = > value . BehaviorKind = = "StatModifier" ) . ToArray ( ) ;
Require ( modifierStates . All ( value = > value . StatModifierApplied & & value . StatModifierTargetStatCount = = 1 ) ,
"applied modifier state must name the exact live target count" ) ;
2026-07-17 03:03:30 +01:00
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , [ ] , catalog , 0.1 ) ;
2026-07-17 02:55:07 +01:00
RequireNear ( 20 , target . EvaluateStat ( 1 ) , 0.000001 ,
"trigger modifiers must disappear on the next tick without another pull" ) ;
2026-07-17 03:03:30 +01:00
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] ,
2026-07-17 02:55:07 +01:00
[ new AetheriaRuntimeDaemonBehaviorIntent
{ ActorEntityKey = "zone.0.entity.0" , EquipmentIndex = 1 , BehaviorIndex = 0 , Active = false } ] ,
2026-07-17 03:03:30 +01:00
catalog , 0.1 ) ;
2026-07-17 02:55:07 +01:00
RequireNear ( 10 , target . EvaluateStat ( 1 ) , 0.000001 ,
"deactivating the switch must restore the unmodified authored stat exactly" ) ;
}
2026-07-17 03:03:30 +01:00
private static void ResourceBehaviorsStopEquipmentChainsInAuthoredOrder ( )
{
var targetItem = CatalogItem ( "resource-target" , new AetheriaRuntimeBehaviorPayload (
0 , "Thruster" , 0 , [ new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 10 ) ) ] ) ) ;
var controlItem = CatalogItem ( "resource-controls" ,
new AetheriaRuntimeBehaviorPayload ( 0 , "Switch" , 0 , [ ] ) ,
new AetheriaRuntimeBehaviorPayload ( 1 , "Cooldown" , 0 ,
[new AetheriaRuntimeBehaviorField(1, PerformanceStat(1))] ) ,
new AetheriaRuntimeBehaviorPayload ( 2 , "EnergyDraw" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 5 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , BoolValue ( false ) )
] ) ,
new AetheriaRuntimeBehaviorPayload ( 3 , "Heat" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 10 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , BoolValue ( false ) )
] ) ,
new AetheriaRuntimeBehaviorPayload ( 4 , "ItemUsage" , 0 ,
[new AetheriaRuntimeBehaviorField(1, ItemKeyValue("resource-ammo"))] ) ,
new AetheriaRuntimeBehaviorPayload ( 5 , "Wear" , 0 ,
[new AetheriaRuntimeBehaviorField(1, BoolValue(true))] ) ,
new AetheriaRuntimeBehaviorPayload ( 6 , "StatModifier" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , StatReference ( "Thruster" , "Thrust" ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , StringValue ( "Multiplier" ) )
] ) ) ;
var capacitorItem = CatalogItem ( "resource-capacitor" , CapacitorPayload ( 10 , 1 ) ) ;
var ammoItem = CatalogItem ( "resource-ammo" ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot (
[targetItem, controlItem, capacitorItem, ammoItem] , [ ] , [ ] ) ;
var entity = Entity ( 0 , 0 , "player" ) ;
entity . Equipment =
[
Equipment ( targetItem . ItemKey ) ,
Equipment ( controlItem . ItemKey ) ,
Equipment ( capacitorItem . ItemKey )
] ;
entity . CargoContents = [ new AetheriaRuntimeCargoBayLoadoutCommit
{
Items = [ new AetheriaRuntimeLoadoutItemSlotCommit
{ Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = ammoItem . ItemKey , Quantity = 2 } } ]
} ] ;
AetheriaRuntimeThermalSimulation . EnsureTopology ( entity , catalog ) ;
AetheriaRuntimeThermalSimulation . EnsureState ( entity ) ;
AetheriaRuntimeThermalSimulation . UpdateEquipmentStates ( entity , catalog , 0.1 ) ;
AetheriaRuntimeBehaviorStateProjector . EnsureEquipmentBehaviorStates ( entity , catalog ) ;
AetheriaRuntimeEnergySimulation . BeginTick ( entity , catalog ) ;
var capacitor = AetheriaRuntimeEquippedBehaviorQueries . Find ( entity , catalog , "Capacitor" ) . Single ( ) ;
capacitor . State . CapacitorCharge = 10 ;
var controlEquipmentState = entity . EquipmentStates . Single ( value = > value . EquipmentIndex = = 1 ) ;
controlEquipmentState . Wear = 2 ;
var initialTemperature = AetheriaRuntimeThermalSimulation . EquipmentTemperature ( entity , catalog , 1 ) ;
var target = AetheriaRuntimeEquippedBehaviorQueries . FindOperational ( entity , catalog , "Thruster" ) . Single ( ) ;
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] ,
[ new AetheriaRuntimeDaemonBehaviorIntent
{ ActorEntityKey = "zone.0.entity.0" , EquipmentIndex = 1 , BehaviorIndex = 0 , Active = true } ] ,
catalog , 0.1 ) ;
RequireNear ( 10 , capacitor . State . CapacitorCharge , 0.000001 ,
"a newly constructed cooldown must stop its group before any resource transaction" ) ;
RequireEqual ( 2 , CargoQuantity ( entity , ammoItem . ItemKey ) ,
"cooldown must stop item usage before cargo mutation" ) ;
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , [ ] , catalog , 0.1 ) ;
RequireNear ( 5 , capacitor . State . CapacitorCharge , 0.000001 ,
"energy draw must debit the daemon capacitor exactly once when the cooldown opens" ) ;
RequireEqual ( 1 , CargoQuantity ( entity , ammoItem . ItemKey ) ,
"item usage must remove exactly one authored cargo item" ) ;
RequireNear ( 0.8 , entity . Equipment [ 1 ] . Item . Durability , 0.000001 ,
"wear must use the thermal owner's pressure only after preceding gates succeed" ) ;
Require ( AetheriaRuntimeThermalSimulation . EquipmentTemperature ( entity , catalog , 1 ) > initialTemperature ,
"heat must enter the source equipment's authoritative thermal cells" ) ;
RequireNear ( 20 , target . EvaluateStat ( 1 ) , 0.000001 ,
"downstream modifiers must apply only after every preceding resource gate succeeds" ) ;
RequireNear ( 0.9 , entity . BehaviorProgress . Single ( value = >
value . OwnerIndex = = 1 & & value . BehaviorKind = = "Cooldown" ) . Progress , 0.000001 ,
"cooldown state must project a generic Eve progress lever from the authoritative behavior row" ) ;
var cooldown = entity . BehaviorStates . Single ( value = >
value . OwnerIndex = = 1 & & value . BehaviorKind = = "Cooldown" ) ;
cooldown . CooldownProgress = - 1 ;
capacitor . State . CapacitorCharge = 0 ;
var temperatureBeforeRefusal = AetheriaRuntimeThermalSimulation . EquipmentTemperature ( entity , catalog , 1 ) ;
var durabilityBeforeRefusal = entity . Equipment [ 1 ] . Item . Durability ;
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , [ ] , catalog , 0.1 ) ;
RequireEqual ( 1 , CargoQuantity ( entity , ammoItem . ItemKey ) ,
"an empty capacitor must stop the group before item usage" ) ;
RequireNear ( durabilityBeforeRefusal , entity . Equipment [ 1 ] . Item . Durability , 0.000001 ,
"an empty capacitor must stop the group before wear" ) ;
RequireNear ( temperatureBeforeRefusal ,
AetheriaRuntimeThermalSimulation . EquipmentTemperature ( entity , catalog , 1 ) , 0.000001 ,
"an empty capacitor must stop the group before heat" ) ;
RequireNear ( 10 , target . EvaluateStat ( 1 ) , 0.000001 ,
"an empty capacitor must remove a downstream modifier instead of leaving stale application state" ) ;
static AetheriaRuntimeLoadoutItemSlotCommit Equipment ( string itemKey ) = > new ( )
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = itemKey , Enabled = true , Durability = 1 , Quality = 1 }
} ;
}
2026-07-17 03:08:56 +01:00
private static void ThermotoggleSeedsAndGatesFromDaemonOwnedTarget ( )
{
var thermostat = CatalogItem ( "thermostat" ,
new AetheriaRuntimeBehaviorPayload ( 0 , "Thermotoggle" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , Number ( 300 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , BoolValue ( false ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , BoolValue ( true ) )
] ) ,
2026-07-17 03:14:26 +01:00
new AetheriaRuntimeBehaviorPayload ( 1 , "Radiator" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , Number ( 200 ) ) ,
new AetheriaRuntimeBehaviorField ( 4 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 5 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 10 ) )
] ) ,
new AetheriaRuntimeBehaviorPayload ( 2 , "Heat" , 0 ,
2026-07-17 03:08:56 +01:00
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 10 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , BoolValue ( false ) )
2026-07-17 03:25:16 +01:00
] ) ,
new AetheriaRuntimeBehaviorPayload ( 3 , "Wear" , 0 ,
[new AetheriaRuntimeBehaviorField(1, BoolValue(true))] ) ) ;
2026-07-17 03:08:56 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ thermostat ] , [ ] , [ ] ) ;
var entity = Entity ( 0 , 0 , "player" ) ;
2026-07-17 03:14:26 +01:00
entity . HeatsinksEnabled = true ;
2026-07-17 03:08:56 +01:00
entity . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = thermostat . ItemKey , Enabled = true , Durability = 1 , Quality = 1 }
} ] ;
AetheriaRuntimeThermalSimulation . EnsureTopology ( entity , catalog ) ;
AetheriaRuntimeThermalSimulation . EnsureState ( entity ) ;
AetheriaRuntimeThermalSimulation . UpdateEquipmentStates ( entity , catalog , 0.1 ) ;
2026-07-17 03:25:16 +01:00
entity . EquipmentStates . Single ( ) . Wear = 1 ;
2026-07-17 03:08:56 +01:00
AetheriaRuntimeBehaviorStateProjector . EnsureEquipmentBehaviorStates ( entity , catalog ) ;
var thermostatState = entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Thermotoggle" ) ;
RequireNear ( 300 , thermostatState . ThermotoggleTargetTemperature , 0.000001 ,
"new thermotoggle state must seed from the authored target instead of zero" ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "thermotoggle-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ]
} ;
var context = new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ;
SetTarget ( 200 , 1 ) ;
var before = AetheriaRuntimeThermalSimulation . EquipmentTemperature ( entity , catalog , 0 ) ;
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , [ ] , catalog , 0.1 ) ;
2026-07-17 03:14:26 +01:00
AetheriaRuntimeEnergySimulation . StepRadiators ( entity , catalog , 0.1 ) ;
2026-07-17 03:25:16 +01:00
AetheriaRuntimeBehaviorSimulation . CompleteDeferredChains ( entity , catalog , 0.1 ) ;
2026-07-17 03:08:56 +01:00
RequireNear ( before , AetheriaRuntimeThermalSimulation . EquipmentTemperature ( entity , catalog , 0 ) , 0.000001 ,
"a low-pass thermotoggle above its target must stop downstream heat" ) ;
2026-07-17 03:14:26 +01:00
Require ( ! entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Heat" ) . ChainReached ,
"a closed thermostat must keep downstream specialized and common behaviors unreachable" ) ;
2026-07-17 03:25:16 +01:00
Require ( ! entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Radiator" ) . ChainSucceeded ,
"a closed thermostat must keep the radiator Execute path from succeeding" ) ;
2026-07-17 03:14:26 +01:00
RequireNear ( 0 , entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Radiator" ) . PumpedHeat , 0.000001 ,
2026-07-17 03:25:16 +01:00
"a closed thermostat must not refresh Execute-owned radiator throughput" ) ;
RequireNear ( 1 , entity . Equipment [ 0 ] . Item . Durability , 0.000001 ,
"a closed thermostat must not apply trailing wear" ) ;
2026-07-17 03:08:56 +01:00
SetTarget ( 300 , 2 ) ;
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , [ ] , catalog , 0.1 ) ;
2026-07-17 03:14:26 +01:00
AetheriaRuntimeEnergySimulation . StepRadiators ( entity , catalog , 0.1 ) ;
2026-07-17 03:25:16 +01:00
AetheriaRuntimeBehaviorSimulation . CompleteDeferredChains ( entity , catalog , 0.1 ) ;
2026-07-17 03:08:56 +01:00
Require ( AetheriaRuntimeThermalSimulation . EquipmentTemperature ( entity , catalog , 0 ) > before ,
"a low-pass thermotoggle below its target must admit downstream heat" ) ;
2026-07-17 03:14:26 +01:00
Require ( entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Heat" ) . ChainReached ,
"an open thermostat must publish that the downstream behavior was reached this tick" ) ;
RequireNear ( 1 , entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Radiator" ) . PumpedHeat , 0.000001 ,
"an open thermostat must admit the radiator subsystem through the same chain state" ) ;
2026-07-17 03:25:16 +01:00
RequireNear ( 0.9 , entity . Equipment [ 0 ] . Item . Durability , 0.000001 ,
"a successful radiator must apply its authored trailing wear exactly once" ) ;
var radiatorPayload = thermostat . BehaviorPayloads . Single ( value = > value . Kind = = "Radiator" ) ;
radiatorPayload . Fields = radiatorPayload . Fields . Select ( field = > field . Key = = 5
? new AetheriaRuntimeBehaviorField ( 5 , PerformanceStat ( 10 ) )
: field ) . ToArray ( ) ;
var durabilityBeforeEnergyRefusal = entity . Equipment [ 0 ] . Item . Durability ;
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , [ ] , catalog , 0.1 ) ;
AetheriaRuntimeEnergySimulation . StepRadiators ( entity , catalog , 0.1 ) ;
AetheriaRuntimeBehaviorSimulation . CompleteDeferredChains ( entity , catalog , 0.1 ) ;
Require ( ! entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Radiator" ) . ChainSucceeded ,
"an unfunded radiator must report its fossil Execute failure" ) ;
RequireNear ( durabilityBeforeEnergyRefusal , entity . Equipment [ 0 ] . Item . Durability , 0.000001 ,
"an unfunded radiator must stop the chain before trailing wear" ) ;
2026-07-17 03:08:56 +01:00
void SetTarget ( double target , long sequence )
{
var command = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . SetThermotoggleTargetTemperature ,
"smoke" , "thermostat-session" , sequence , "zone.0.entity.0" ) ;
command . TargetEntityKey = "zone.0.entity.0" ;
command . EquipmentIndex = 0 ;
command . BehaviorIndex = 0 ;
command . ScalarValue = target ;
var result = AetheriaRuntimeDaemonOperations . Execute ( run , [ command ] , context ) ;
RequireEqual ( 1 , result . AppliedCommandIds . Count ,
"an installed adjustable thermotoggle must accept its typed daemon command" ) ;
}
}
2026-07-17 03:37:49 +01:00
private static void InputCapabilityPublishesExactBehaviorLevers ( )
{
var controls = CatalogItem ( "behavior-controls" ,
new AetheriaRuntimeBehaviorPayload ( 0 , "Thruster" , 0 , [ ] ) ,
new AetheriaRuntimeBehaviorPayload ( 1 , "Switch" , 1 , [ ] ) ,
new AetheriaRuntimeBehaviorPayload ( 2 , "Trigger" , 2 , [ ] ) ,
new AetheriaRuntimeBehaviorPayload ( 3 , "Thermotoggle" , 3 ,
[
new AetheriaRuntimeBehaviorField ( 1 , Number ( 300 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , BoolValue ( false ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , BoolValue ( true ) )
] ) ,
new AetheriaRuntimeBehaviorPayload ( 4 , "Thermotoggle" , 4 ,
[
new AetheriaRuntimeBehaviorField ( 1 , Number ( 350 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , BoolValue ( false ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , BoolValue ( false ) )
] ) ) ;
controls . Name = "Climate Control" ;
2026-07-17 05:32:43 +01:00
controls . ActionBarIcon = "Assets/Resources/Sprites/Icons/Stroked/Power.png" ;
2026-07-17 03:37:49 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ controls ] , [ ] , [ ] ) ;
var entity = Entity ( 0 , 0 , "player" ) ;
entity . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = controls . ItemKey , Enabled = true , Durability = 1 , Quality = 1 }
} ] ;
AetheriaRuntimeBehaviorStateProjector . EnsureEquipmentBehaviorStates ( entity , catalog ) ;
entity . EquipmentStates = [ new AetheriaRuntimeEquipmentStateCommit
{ EquipmentIndex = 0 , Online = true } ] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "behavior-input-smoke" ,
CurrentZoneIndex = 0 ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ]
} ;
run . CurrentEntityKey = run . EntityRecordKey ( 0 , entity . EntityIndex ) ;
var frame = AetheriaRuntimeDaemonFrameDocument . Create ( run , "smoke" , "behavior-input" , 1 , 0.1 , 0.1 ) ;
var capability = AetheriaRuntimeInputCapabilityDocument . FromFrame ( frame , catalog : catalog ) ;
RequireEqual ( "aetheria" , capability . ProviderId ,
"input capability must retain provider identity instead of substituting daemon service identity" ) ;
var actions = capability . Actions . Where ( value = > value . Category = = "equipment" ) . ToArray ( ) ;
RequireEqual ( 3 , actions . Length ,
"input capability must omit non-interactive and fixed behaviors instead of activating behavior zero blindly" ) ;
var switchAction = actions . Single ( value = > value . ActionId = = "equipment.0.behavior.1" ) ;
var triggerAction = actions . Single ( value = > value . ActionId = = "equipment.0.behavior.2" ) ;
var thermostatAction = actions . Single ( value = > value . ActionId = = "equipment.0.behavior.3" ) ;
RequireEqual ( "button-hold.v1" , switchAction . InputValue ? . Model ? ? "" ,
"switch controls must advertise the fossil press/release input model" ) ;
RequireEqual ( "active" , triggerAction . InputValue ? . PayloadKey ? ? "" ,
"trigger controls must route their input value into the typed active field" ) ;
RequireEqual ( "scalar.v1" , thermostatAction . InputValue ? . Model ? ? "" ,
"adjustable thermostats must advertise a runtime-neutral scalar lever" ) ;
2026-07-17 05:32:43 +01:00
RequireNear ( 300 , thermostatAction . InputValue ? . CurrentValue ? ? double . NaN , 0.000001 ,
"thermostat controls must publish the daemon-owned current target as typed scalar state" ) ;
RequireEqual ( "kelvin" , thermostatAction . InputValue ? . Unit ? ? "" ,
"thermostat controls must publish the scalar unit without hiding it in command payload strings" ) ;
Require ( actions . All ( value = > value . ActionBar & & value . IconRef = = "item.behavior-controls.icon" ) ,
"interactive equipment behaviors must expose provider-icon action-bar suggestions" ) ;
var portableThermostat = capability . ToEveDocument ( ) . Actions
. Single ( value = > value . ActionId = = thermostatAction . ActionId ) ;
RequireNear ( 300 , portableThermostat . InputValue ? . CurrentValue ? ? double . NaN , 0.000001 ,
"the portable Eve document must retain typed scalar current state" ) ;
Require ( portableThermostat . ActionBar & & portableThermostat . IconRef = = "item.behavior-controls.icon" ,
"the portable Eve action must retain the provider action-bar suggestion and asset key" ) ;
2026-07-17 03:37:49 +01:00
var switchRequest = new EveSurfaceCommandRequest (
capability . ProviderId ,
AetheriaRuntimeDaemonGameSurfaceBuilder . PilotSurfaceId ,
CultMesh . OperationInvocation ( switchAction . Operation ) ,
CultMesh . OperationPayload (
( "entityId" , run . CurrentEntityKey ) ,
( "equipmentIndex" , "0" ) ,
( "behaviorIndex" , "1" ) ,
( "active" , "1" ) ) ,
DateTimeOffset . UtcNow ,
"behavior-input-smoke" ) ;
var switchTranslated = AetheriaRuntimeDaemonOperationsClient . TryCreateSurfaceCommandDocument (
switchRequest , frame , "." , "behavior-input-smoke" , "behavior-input" , out var switchCommand ) ;
Require ( switchTranslated & &
switchCommand ? . Kind = = AetheriaRuntimeDaemonCommandKinds . SetBehaviorActive & &
switchCommand . EquipmentIndex = = 0 & & switchCommand . BehaviorIndex = = 1 & &
switchCommand . ScalarValue > 0.5 ,
$"the generic Eve action must translate into the exact typed switch command; accepted={switchTranslated}, kind={switchCommand?.Kind}, equipment={switchCommand?.EquipmentIndex}, behavior={switchCommand?.BehaviorIndex}, scalar={switchCommand?.ScalarValue}" ) ;
var switchResult = AetheriaRuntimeDaemonOperations . Execute (
run , [ switchCommand ! ] , new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ) ;
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , switchResult . Intents . Behaviors , catalog , 0.1 ) ;
Require ( entity . BehaviorStates . Single ( value = > value . BehaviorIndex = = 1 ) . SwitchActivated ,
"the advertised switch lever must reach the daemon behavior owner" ) ;
var thermostatRequest = new EveSurfaceCommandRequest (
capability . ProviderId ,
AetheriaRuntimeDaemonGameSurfaceBuilder . PilotSurfaceId ,
CultMesh . OperationInvocation ( thermostatAction . Operation ) ,
CultMesh . OperationPayload (
( "entityId" , run . CurrentEntityKey ) ,
( "targetEntityKey" , run . CurrentEntityKey ) ,
( "equipmentIndex" , "0" ) ,
( "behaviorIndex" , "3" ) ,
( "scalarValue" , "425" ) ) ,
DateTimeOffset . UtcNow ,
"behavior-input-smoke" ) ;
Require ( AetheriaRuntimeDaemonOperationsClient . TryCreateSurfaceCommandDocument (
thermostatRequest , frame , "." , "behavior-input-smoke" , "behavior-input" , out var thermostatCommand ) & &
thermostatCommand ? . Kind = = AetheriaRuntimeDaemonCommandKinds . SetThermotoggleTargetTemperature ,
"the generic Eve scalar lever must translate into the typed thermostat command" ) ;
var thermostatResult = AetheriaRuntimeDaemonOperations . Execute (
run , [ thermostatCommand ! ] , new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ) ;
RequireEqual ( 1 , thermostatResult . AppliedCommandIds . Count ,
"the translated thermostat command must pass daemon catalog authorization" ) ;
RequireNear ( 425 , entity . BehaviorStates . Single ( value = > value . BehaviorIndex = = 3 )
. ThermotoggleTargetTemperature , 0.000001 ,
"the advertised scalar lever must mutate only daemon-owned thermostat state" ) ;
entity . EquipmentStates [ 0 ] . Online = false ;
var offline = AetheriaRuntimeInputCapabilityDocument . FromFrame ( frame , catalog : catalog ) ;
Require ( offline . Actions . Where ( value = > value . Category = = "equipment" )
. All ( value = > value . Availability = = "unavailable" ) ,
"offline equipment must retain stable action identity while advertising current unavailability" ) ;
}
2026-07-17 04:37:35 +01:00
private static void InputCapabilityPublishesConsumableActionBarState ( )
{
var repairGel = CatalogItem ( "repair-gel" ) ;
repairGel . Name = "Repair Gel" ;
repairGel . Category = AetheriaRuntimeItemCategories . Consumable ;
repairGel . Duration = 4 ;
repairGel . Stackable = false ;
2026-07-17 05:32:43 +01:00
repairGel . ActionBarIcon = "Assets/Resources/Sprites/Icons/Stroked/Repair.png" ;
2026-07-17 04:37:35 +01:00
var ore = CatalogItem ( "ore" ) ;
ore . Category = AetheriaRuntimeItemCategories . SimpleCommodity ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ repairGel , ore ] , [ ] , [ ] ) ;
var entity = Entity ( 0 , 0 , "player" ) ;
entity . CargoContents =
[
new AetheriaRuntimeCargoBayLoadoutCommit
{
Items =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "repair-gel" , Quantity = 3 }
} ,
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "ore" , Quantity = 7 }
}
]
}
] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "consumable-input-smoke" ,
CurrentZoneIndex = 0 ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ]
} ;
run . CurrentEntityKey = run . EntityRecordKey ( 0 , entity . EntityIndex ) ;
var frame = AetheriaRuntimeDaemonFrameDocument . Create ( run , "smoke" , "consumable-input" , 1 , 0.1 , 0.1 ) ;
var capability = AetheriaRuntimeInputCapabilityDocument . FromFrame ( frame , catalog : catalog ) ;
var action = capability . Actions . Single ( value = > value . Category = = "consumable" ) ;
RequireEqual ( "3" , action . Payload [ "quantityRemaining" ] ,
"consumable action bars must derive quantity from daemon cargo truth" ) ;
RequireEqual ( "0" , action . Payload [ "fillValue" ] ,
"inactive consumables must advertise an empty remaining-duration fill" ) ;
RequireEqual ( "remaining-ratio.v1" , action . Payload [ "fillModel" ] ,
"generic lowerers must receive the fossil action-bar fill semantics explicitly" ) ;
RequireEqual ( "available" , action . Availability ,
"a valid consumable in cargo must advertise current command availability" ) ;
2026-07-17 05:32:43 +01:00
Require ( action . ActionBar & & action . IconRef = = "item.repair-gel.icon" ,
"consumables must suggest an action-bar lever using their provider-owned catalog icon" ) ;
2026-07-17 04:37:35 +01:00
Require ( ! capability . Actions . Any ( value = > value . Category = = "consumable" & & value . Payload [ "itemKey" ] = = "ore" ) ,
"non-consumable cargo must not become an action-bar command" ) ;
entity . CargoContents = Array . Empty < AetheriaRuntimeCargoBayLoadoutCommit > ( ) ;
entity . ActiveConsumables =
[
new AetheriaRuntimeActiveConsumableCommit
{
ItemKey = "repair-gel" ,
Duration = 4 ,
RemainingDuration = 1
}
] ;
var activeAction = AetheriaRuntimeInputCapabilityDocument . FromFrame ( frame , catalog : catalog )
. ToEveDocument ( ) . Actions . Single ( value = > value . Category = = "consumable" ) ;
RequireEqual ( "0" , activeAction . Payload [ "quantityRemaining" ] ,
"the action must survive depletion while its daemon-owned effect remains active" ) ;
RequireEqual ( "1" , activeAction . Payload [ "activeEffectCount" ] ,
"the portable Eve action must expose daemon-owned active effect state" ) ;
RequireEqual ( "1" , activeAction . Payload [ "remainingDurationSeconds" ] ,
"generic clients must receive exact remaining duration without querying a Unity effect object" ) ;
RequireEqual ( "4" , activeAction . Payload [ "durationSeconds" ] ,
"generic clients must receive exact authored consumable duration" ) ;
RequireEqual ( "0.25" , activeAction . Payload [ "fillValue" ] ,
"remaining duration must lower to the fossil action-bar ratio exactly" ) ;
RequireEqual ( "unavailable" , activeAction . Availability ,
"a depleted non-stackable active consumable must remain visible but reject activation" ) ;
}
2026-07-17 03:46:33 +01:00
private static void InputCapabilityPublishesHeldWeaponGroupLever ( )
{
var entity = Entity ( 0 , 0 , "player" ) ;
entity . WeaponGroups = [ new [ ] { 0 } ] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "weapon-input-smoke" ,
CurrentZoneIndex = 0 ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ]
} ;
run . CurrentEntityKey = run . EntityRecordKey ( 0 , entity . EntityIndex ) ;
var frame = AetheriaRuntimeDaemonFrameDocument . Create ( run , "smoke" , "weapon-input" , 1 , 0.1 , 0.1 ) ;
var capability = AetheriaRuntimeInputCapabilityDocument . FromFrame ( frame ) ;
var action = capability . Actions . Single ( value = > value . ActionId = = "weapon-group.0.fire" ) ;
RequireEqual ( "aetheria.daemon.commands.SetWeaponGroupActive" , action . Operation ,
"weapon input must advertise the daemon's press/release owner instead of the one-shot compatibility command" ) ;
RequireEqual ( "button-hold.v1" , action . InputValue ? . Model ? ? "" ,
"generic Eve clients must know that weapon firing is a held control" ) ;
RequireEqual ( "active" , action . InputValue ? . PayloadKey ? ? "" ,
"weapon press/release values must route into the typed active field" ) ;
2026-07-17 05:32:43 +01:00
Require ( action . ActionBar ,
"weapon groups must remain suggested action-bar levers without making the client own firing" ) ;
2026-07-17 03:46:33 +01:00
AetheriaRuntimeDaemonCommandDocument Translate ( string active )
{
var request = new EveSurfaceCommandRequest (
capability . ProviderId ,
AetheriaRuntimeDaemonGameSurfaceBuilder . PilotSurfaceId ,
CultMesh . OperationInvocation ( action . Operation ) ,
CultMesh . OperationPayload (
( "entityId" , run . CurrentEntityKey ) ,
( "weaponGroup" , "0" ) ,
( "active" , active ) ) ,
DateTimeOffset . UtcNow ,
"weapon-input-smoke" ) ;
Require ( AetheriaRuntimeDaemonOperationsClient . TryCreateSurfaceCommandDocument (
request , frame , "." , "weapon-input-smoke" , "weapon-input" , out var command ) & &
command ? . Kind = = AetheriaRuntimeDaemonCommandKinds . SetWeaponGroupActive ,
$"generic weapon input value {active} must translate into the typed held-fire command" ) ;
return command ! ;
}
var pressed = AetheriaRuntimeDaemonOperations . Execute (
run , [ Translate ( "1" ) ] , new AetheriaRuntimeDaemonOperationContext ( ) ) ;
RequireEqual ( 1 , pressed . Intents . WeaponGroups . Count ,
"weapon press must reach the daemon intent owner exactly once" ) ;
Require ( pressed . Intents . WeaponGroups [ 0 ] . Active ,
"weapon press must activate the exact advertised group" ) ;
2026-07-17 03:54:33 +01:00
Require ( entity . ActiveWeaponGroups . SequenceEqual ( new [ ] { true } ) ,
"weapon press must persist the daemon-owned held state beyond its command frame" ) ;
var heldCapability = AetheriaRuntimeInputCapabilityDocument . FromFrame ( frame ) ;
RequireEqual ( "1" , heldCapability . Actions . Single ( value = > value . ActionId = = "weapon-group.0.fire" )
. Payload [ "currentValue" ] ,
"the Eve lever must derive its current value from the daemon-owned held state" ) ;
var restartedRun = MessagePack . MessagePackSerializer . Deserialize < AetheriaRuntimeRunCheckpointCommit > (
MessagePack . MessagePackSerializer . Serialize ( run ) ) ;
var restartedFrame = AetheriaRuntimeDaemonFrameDocument . Create (
restartedRun , "smoke" , "weapon-input-restart" , 2 , 0.2 , 0.1 ) ;
Require ( restartedRun . Zones [ 0 ] . Entities [ 0 ] . ActiveWeaponGroups . SequenceEqual ( new [ ] { true } ) & &
AetheriaRuntimeInputCapabilityDocument . FromFrame ( restartedFrame ) . Actions
. Single ( value = > value . ActionId = = "weapon-group.0.fire" ) . Payload [ "currentValue" ] = = "1" ,
"daemon restart must retain held weapon-group truth and re-advertise it through Eve" ) ;
2026-07-17 03:46:33 +01:00
var released = AetheriaRuntimeDaemonOperations . Execute (
run , [ Translate ( "0" ) ] , new AetheriaRuntimeDaemonOperationContext ( ) ) ;
RequireEqual ( 1 , released . Intents . WeaponGroups . Count ,
"weapon release must reach the daemon intent owner exactly once" ) ;
Require ( ! released . Intents . WeaponGroups [ 0 ] . Active ,
"weapon release must deactivate the exact advertised group" ) ;
2026-07-17 03:54:33 +01:00
Require ( entity . ActiveWeaponGroups . SequenceEqual ( new [ ] { false } ) ,
"weapon release must clear the daemon-owned held state" ) ;
2026-07-17 03:46:33 +01:00
}
2026-07-17 04:42:42 +01:00
private static void InputCapabilityPublishesNativeTargetAndInteractControls ( )
{
var actor = Entity ( 0 , 0 , "player" ) ;
var near = Entity ( 1 , 0 , "enemy" ) ;
near . PositionX = 4 ;
var far = Entity ( 2 , 0 , "enemy" ) ;
2026-07-17 05:05:40 +01:00
far . PositionZ = 12 ;
2026-07-17 04:42:42 +01:00
actor . Contacts =
[
new AetheriaRuntimeEntityContactCommit
{ TargetEntityIndex = near . EntityIndex , Visible = true , Hostile = true } ,
new AetheriaRuntimeEntityContactCommit
{ TargetEntityIndex = far . EntityIndex , Visible = true , Hostile = true }
] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "native-input-smoke" ,
CurrentZoneIndex = 0 ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ actor , near , far ] } ]
} ;
run . CurrentEntityKey = run . EntityRecordKey ( 0 , actor . EntityIndex ) ;
var frame = AetheriaRuntimeDaemonFrameDocument . Create ( run , "smoke" , "native-input" , 1 , 0.1 , 0.1 ) ;
var capability = AetheriaRuntimeInputCapabilityDocument . FromFrame ( frame ) ;
var targeting = capability . Actions . Where ( value = > value . Category = = "targeting" ) . ToArray ( ) ;
Require ( targeting . Select ( value = > value . ActionId ) . ToHashSet ( StringComparer . Ordinal ) . SetEquals (
2026-07-17 05:05:40 +01:00
["pilot.target-nearest", "pilot.target-previous", "pilot.target-next", "pilot.target-reticle", "pilot.target-clear"] ) ,
"portable input must advertise every daemon target-selection lever" ) ;
2026-07-17 04:42:42 +01:00
Require ( targeting . Where ( value = > value . ActionId ! = "pilot.target-clear" )
. All ( value = > value . Availability = = "available" & &
value . Payload [ "visibleHostileCount" ] = = "2" & &
value . Payload [ "currentTargetEntityIndex" ] = = "-1" ) & &
targeting . Single ( value = > value . ActionId = = "pilot.target-clear" ) . Availability = = "unavailable" ,
"target controls must derive availability and current selection from daemon contact truth" ) ;
var keyboard = capability . DefaultProfiles . Single ( value = > value . DeviceClass = = "keyboard-mouse" ) ;
string Control ( string actionId ) = > keyboard . Bindings . Single ( value = > value . ActionId = = actionId ) . Gesture . Controls . Single ( ) ;
RequireEqual ( "keyboard.f" , Control ( "pilot.interact" ) ,
"the generic default profile must preserve the fossil interaction key" ) ;
RequireEqual ( "keyboard.t" , Control ( "pilot.target-nearest" ) ,
"the generic default profile must preserve the fossil nearest-target key" ) ;
RequireEqual ( "keyboard.y" , Control ( "pilot.target-previous" ) ,
"the generic default profile must preserve the fossil previous-target key" ) ;
RequireEqual ( "keyboard.u" , Control ( "pilot.target-next" ) ,
"the generic default profile must preserve the fossil next-target key" ) ;
2026-07-17 05:05:40 +01:00
RequireEqual ( "keyboard.r" , Control ( "pilot.target-reticle" ) ,
"the generic default profile must preserve the fossil reticle-target key" ) ;
2026-07-17 05:32:43 +01:00
Require ( keyboard . Bindings . Where ( value = > value . ActionId = = "pilot.interact" | |
value . ActionId . StartsWith ( "pilot.target-" , StringComparison . Ordinal ) )
. All ( value = > ! value . ActionBar ) ,
"ordinary fossil shortcuts must not masquerade as action-bar slot suggestions" ) ;
2026-07-17 05:05:40 +01:00
var reticleAction = capability . ToEveDocument ( ) . Actions . Single ( value = > value . ActionId = = "pilot.target-reticle" ) ;
RequireEqual ( "view-direction.v1" , reticleAction . InputValue ? . Model ? ? "" ,
"reticle targeting must advertise the generic active-view direction model" ) ;
Require ( ( reticleAction . InputValue ? . PayloadKeys ? ? Array . Empty < string > ( ) ) . SequenceEqual (
["directionX", "directionY", "directionZ"] ) ,
"reticle targeting must preserve the portable world-direction payload order" ) ;
2026-07-17 04:42:42 +01:00
AetheriaRuntimeDaemonCommandDocument Translate ( AetheriaRuntimeInputActionDocument action )
{
var request = new EveSurfaceCommandRequest (
capability . ProviderId ,
AetheriaRuntimeDaemonGameSurfaceBuilder . PilotSurfaceId ,
CultMesh . OperationInvocation ( action . Operation ) ,
CultMesh . OperationPayload ( ( "entityId" , run . CurrentEntityKey ) ) ,
DateTimeOffset . UtcNow ,
"native-input-smoke" ) ;
Require ( AetheriaRuntimeDaemonOperationsClient . TryCreateSurfaceCommandDocument (
request , frame , "." , "native-input-smoke" , "native-input" , out var command ) ,
$"advertised action {action.ActionId} must translate through the generic Eve command path" ) ;
return command ! ;
}
var nearestCommand = Translate ( targeting . Single ( value = > value . ActionId = = "pilot.target-nearest" ) ) ;
RequireEqual ( AetheriaRuntimeDaemonCommandKinds . TargetNearest , nearestCommand . Kind ,
"nearest target action must preserve daemon command identity" ) ;
var result = AetheriaRuntimeDaemonOperations . Execute (
run , [ nearestCommand ] , new AetheriaRuntimeDaemonOperationContext ( ) ) ;
RequireEqual ( 1 , result . AppliedCommandIds . Count ,
"the advertised target action must reach the daemon owner" ) ;
RequireEqual ( near . EntityIndex , actor . TargetEntityIndex ,
"nearest selection must remain daemon policy rather than client reconstruction" ) ;
var selected = AetheriaRuntimeInputCapabilityDocument . FromFrame ( frame ) ;
Require ( selected . Actions . Single ( value = > value . ActionId = = "pilot.target-clear" ) . Availability = = "available" & &
selected . Actions . Where ( value = > value . Category = = "targeting" )
. All ( value = > value . Payload [ "currentTargetEntityIndex" ] = = near . EntityIndex . ToString ( ) ) ,
"all portable target levers must refresh from the newly selected daemon target" ) ;
2026-07-17 05:05:40 +01:00
var reticleRequest = new EveSurfaceCommandRequest (
capability . ProviderId ,
AetheriaRuntimeDaemonGameSurfaceBuilder . PilotSurfaceId ,
CultMesh . OperationInvocation ( reticleAction . Operation ) ,
CultMesh . OperationPayload (
( "entityId" , run . CurrentEntityKey ) ,
( "directionX" , "0" ) ,
( "directionY" , "0" ) ,
( "directionZ" , "1" ) ) ,
DateTimeOffset . UtcNow ,
"native-input-smoke" ) ;
Require ( AetheriaRuntimeDaemonOperationsClient . TryCreateSurfaceCommandDocument (
reticleRequest , frame , "." , "native-input-smoke" , "native-input" , out var reticleCommand ) & &
reticleCommand ? . Kind = = AetheriaRuntimeDaemonCommandKinds . TargetReticle ,
"the generic Eve view-direction action must translate into the typed reticle command" ) ;
var reticleResult = AetheriaRuntimeDaemonOperations . Execute (
run , [ reticleCommand ! ] , new AetheriaRuntimeDaemonOperationContext ( ) ) ;
RequireEqual ( 1 , reticleResult . AppliedCommandIds . Count ,
"the translated reticle action must reach the daemon target owner" ) ;
RequireEqual ( far . EntityIndex , actor . TargetEntityIndex ,
"reticle selection must rank visible hostile contacts from the advertised view ray inside the daemon" ) ;
2026-07-17 04:42:42 +01:00
var interact = capability . Actions . Single ( value = > value . ActionId = = "pilot.interact" ) ;
RequireEqual ( AetheriaRuntimeDaemonCommandKinds . Interact , Translate ( interact ) . Kind ,
"the fossil interaction binding must reach the shared wormhole-first/then-dock daemon command" ) ;
}
2026-07-17 01:45:33 +01:00
private static void DockedRefitSurfacePublishesGenericCommands ( )
{
var hull = HullCatalogItem ( "surface-hull" , 9 , 7 , 100 ) ;
var cargoBay = CatalogItem ( "surface-cargo-bay" ) ;
cargoBay . InteriorShapeWidth = 6 ;
cargoBay . InteriorShapeHeight = 4 ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , cargoBay , CatalogItem ( "ore" ) ] , [ ] , [ ] ) ;
var ship = Entity ( 0 , 0 , "player" ) ;
ship . Name = "Pilot" ;
ship . HullItemKey = hull . ItemKey ;
ship . CargoBays = [ ItemSlot ( cargoBay . ItemKey ) ] ;
ship . CargoContents = [ new AetheriaRuntimeCargoBayLoadoutCommit { Items = [ ItemSlot ( "ore" , 2 , 3 ) ] } ] ;
var station = Entity ( 1 , 0 , "player" ) ;
station . Kind = "station" ;
station . Name = "Station" ;
station . DockingBayAssignments = [ ship . EntityIndex ] ;
station . CargoBays = [ ItemSlot ( cargoBay . ItemKey ) ] ;
station . CargoContents = [ new AetheriaRuntimeCargoBayLoadoutCommit ( ) ] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "generic-refit-surface-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship , station ] } ]
} ;
var frame = AetheriaRuntimeDaemonFrameDocument . Create ( run , "smoke" , "surface" , 1 , 0.02 , 0.02 ) ;
var shipKey = run . EntityRecordKey ( 0 , ship . EntityIndex ) ;
var stationKey = run . EntityRecordKey ( 0 , station . EntityIndex ) ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
frame ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "smoke" ) ,
catalog : catalog ) ;
var equipment = Find ( surface . Surface . Root , "aetheria.daemon.game.refit.ship.equipment" ) ;
var shipCargo = Find ( surface . Surface . Root , "aetheria.daemon.game.refit.ship.cargo.0" ) ;
var stationCargo = Find ( surface . Surface . Root , "aetheria.daemon.game.refit.station.cargo.0" ) ;
Require ( equipment ! = null & & equipment . Kind = = "inventory.grid" & &
equipment . Props [ "columns" ] = = "9" & & equipment . Props [ "rows" ] = = "7" ,
"docked pilot surface must publish authored ship equipment geometry" ) ;
Require ( shipCargo ! = null & & stationCargo ! = null & &
shipCargo . Props [ "targetEntityKey" ] = = shipKey & &
stationCargo . Props [ "targetEntityKey" ] = = stationKey ,
"docked pilot surface must publish both ship and station cargo targets" ) ;
Require ( surface . Commands . Any ( value = > value . Command = =
AetheriaRuntimeDaemonSurfaceCommandCatalog . CommandName ( AetheriaRuntimeDaemonCommandKinds . TransferCargoItem ) ) & &
surface . Commands . Any ( value = > value . Command = =
AetheriaRuntimeDaemonSurfaceCommandCatalog . CommandName ( AetheriaRuntimeDaemonCommandKinds . EquipItem ) ) & &
surface . Commands . Any ( value = > value . Command = =
AetheriaRuntimeDaemonSurfaceCommandCatalog . CommandName ( AetheriaRuntimeDaemonCommandKinds . StoreItem ) ) ,
"docked pilot surface must advertise all atomic refit operations" ) ;
var request = new EveSurfaceCommandRequest (
"aetheria" ,
AetheriaRuntimeDaemonGameSurfaceBuilder . PilotSurfaceId ,
CultMesh . OperationInvocation (
AetheriaRuntimeDaemonSurfaceCommandCatalog . CommandName ( AetheriaRuntimeDaemonCommandKinds . TransferCargoItem ) ) ,
CultMesh . OperationPayload (
( "entityId" , shipKey ) ,
( "originEntityKey" , shipKey ) ,
( "originCargoIndex" , "0" ) ,
( "destinationEntityKey" , stationKey ) ,
( "destinationCargoIndex" , "0" ) ,
( "itemKey" , "ore" ) ,
( "quantity" , "1" ) ,
( "sourceX" , "2" ) ,
( "sourceY" , "3" ) ,
( "destinationX" , "0" ) ,
( "destinationY" , "0" ) ,
( "hasDestinationPosition" , "true" ) ) ,
DateTimeOffset . UtcNow ,
"generic-smoke" ) ;
Require ( AetheriaRuntimeDaemonOperationsClient . TryCreateSurfaceCommandDocument (
request , frame , "." , "generic-smoke" , "surface" , out var translated ) & &
translated ? . CargoTransfer . OriginCargoIndex = = 0 & &
translated . CargoTransfer . DestinationEntityKey = = stationKey & &
translated . CargoTransfer . HasDestinationPosition ,
"generic Eve inventory drop must translate into the exact typed daemon cargo command" ) ;
var unauthorized = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . TransferCargoItem ,
"generic-smoke" , "surface" , 1 , shipKey ) ;
unauthorized . TextValue = "ore" ;
unauthorized . CargoTransfer . OriginEntityKey = stationKey ;
unauthorized . CargoTransfer . DestinationEntityKey = stationKey ;
unauthorized . CargoTransfer . OriginCargoIndex = 0 ;
unauthorized . CargoTransfer . DestinationCargoIndex = 0 ;
var rejected = AetheriaRuntimeDaemonOperations . Execute ( run , [ unauthorized ] ,
new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ) ;
Require ( rejected . RejectedCommandReasons [ unauthorized . CommandId ] = =
AetheriaRuntimeDaemonRejectionReasons . CargoAccessDenied ,
"cargo transfer actor must own one endpoint even when the target is physically nearby" ) ;
station . DockingBayAssignments = [ ] ;
var undocked = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
frame ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "smoke" ) ,
catalog : catalog ) ;
Require ( Find ( undocked . Surface . Root , "aetheria.daemon.game.refit" ) = = null ,
"undocked pilot surfaces must not expose station refit controls" ) ;
static AetheriaRuntimeSurfaceComponent ? Find ( AetheriaRuntimeSurfaceComponent component , string id ) = >
component . Id = = id
? component
: component . Children . Select ( child = > Find ( child , id ) ) . FirstOrDefault ( value = > value ! = null ) ;
static AetheriaRuntimeLoadoutItemSlotCommit ItemSlot ( string itemKey , int x = 0 , int y = 0 ) = > new ( )
{
X = x ,
Y = y ,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = itemKey ,
Quantity = 1 ,
Quality = 1 ,
Durability = 1 ,
Enabled = true
}
} ;
}
2026-07-17 01:52:36 +01:00
private static void FossilVelocityBehaviorsRunInDaemonFlightStep ( )
{
var conversion = new AetheriaRuntimeBehaviorPayload (
0 ,
AetheriaRuntimeBehaviorKinds . VelocityConversion ,
0 ,
[new AetheriaRuntimeBehaviorField(1, PerformanceStat(Math.Log(2)))] ) ;
var limit = new AetheriaRuntimeBehaviorPayload (
1 ,
AetheriaRuntimeBehaviorKinds . VelocityLimit ,
0 ,
[new AetheriaRuntimeBehaviorField(1, PerformanceStat(4))] ) ;
var hull = HullCatalogItem ( "velocity-hull" , 1 , 1 , 100 ) ;
var controller = CatalogItem ( "velocity-controller" , conversion , limit ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , controller ] , [ ] , [ ] ) ;
var ship = Entity ( 0 , 0 , "player" ) ;
ship . HullItemKey = hull . ItemKey ;
ship . DirectionX = 1 ;
ship . DirectionY = 0 ;
ship . VelocityX = 0 ;
ship . VelocityY = 10 ;
ship . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = controller . ItemKey ,
Quantity = 1 ,
Quality = 1 ,
Durability = 1 ,
Enabled = true
}
}
] ;
AetheriaRuntimeBehaviorStateProjector . EnsureEquipmentBehaviorStates ( ship , catalog ) ;
AetheriaRuntimeFlightSimulation . Step ( [ ship ] , [ ] , catalog , 1 , 1 , 1 , 0 , 1 ) ;
RequireNear ( 4 , Math . Sqrt ( ship . VelocityX * ship . VelocityX + ship . VelocityY * ship . VelocityY ) , 0.000001 ,
"VelocityLimit must clamp the post-conversion speed in the authoritative flight step" ) ;
RequireNear ( ship . VelocityX , ship . VelocityY , 0.000001 ,
"VelocityConversion must exponentially align velocity toward the ship direction before limiting" ) ;
var limitState = ship . BehaviorStates . Single ( state = >
state . BehaviorKind = = AetheriaRuntimeBehaviorKinds . VelocityLimit ) ;
RequireNear ( 4 , limitState . VelocityLimit , 0.000001 ,
"VelocityLimit must publish its evaluated runtime value for Eve and reconnect" ) ;
}
2026-07-17 02:02:10 +01:00
private static void ReflectorUsesSharedStellarLightFieldWithoutAccumulating ( )
{
var reflector = new AetheriaRuntimeBehaviorPayload (
0 ,
AetheriaRuntimeBehaviorKinds . Reflector ,
0 ,
[new AetheriaRuntimeBehaviorField(1, PerformanceStat(2))] ) ;
2026-07-17 02:05:43 +01:00
var constantVisibility = new AetheriaRuntimeBehaviorPayload (
1 ,
AetheriaRuntimeBehaviorKinds . Visibility ,
0 ,
[new AetheriaRuntimeBehaviorField(1, PerformanceStat(5))] ) ;
var controller = CatalogItem ( "reflector-controller" , reflector , constantVisibility ) ;
2026-07-17 02:02:10 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ controller ] , [ ] , [ ] ) ;
var ship = Entity ( 0 , 250 , "player" ) ;
ship . Visibility = 3 ;
ship . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = controller . ItemKey ,
Quantity = 1 ,
Quality = 1 ,
Durability = 1 ,
Enabled = true
}
}
] ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ ship ] ,
Orbits =
[
new AetheriaRuntimeOrbitSnapshotCommit
{
OrbitKey = "sun-orbit" ,
FixedPositionX = 100
}
] ,
Bodies =
[
new AetheriaRuntimeBodySnapshotCommit
{
Kind = "sun" ,
Mass = 16 ,
OrbitKey = "sun-orbit" ,
SunVisual = new AetheriaRuntimeSunVisualCommit { LightRadiusMultiplier = 1 }
}
]
} ;
var settings = AetheriaRuntimeDaemonRenderSettings . AetheriaDefault ;
var radius = settings . ResolveLightRadius ( 16 ) ;
var pulseX = Math . Min ( 1 , 150 / radius * 2 ) ;
var expectedReflection = 2 * Math . Pow ( ( pulseX + 1 ) * ( 1 - pulseX ) , 8 ) ;
AetheriaRuntimeVisibilitySimulation . StepZone ( zone , [ ship ] , catalog , settings ) ;
AetheriaRuntimeVisibilitySimulation . StepZone ( zone , [ ship ] , catalog , settings ) ;
2026-07-17 02:05:43 +01:00
RequireNear ( 3 + 5 + expectedReflection , ship . Visibility , 0.000001 ,
"Visibility and Reflector must publish their fossil sources without accumulating per tick" ) ;
var equipmentSource = ship . StatGrids . Single ( grid = > grid . Name = = "equipment-visibility" ) ;
RequireNear ( 5 , equipmentSource . Values . Single ( ) , 0.000001 ,
"Operational Visibility equipment must publish its evaluated signature as an inspectable source" ) ;
2026-07-17 02:02:10 +01:00
var source = ship . StatGrids . Single ( grid = > grid . Name = = "reflector-visibility" ) ;
RequireNear ( expectedReflection , source . Values . Single ( ) , 0.000001 ,
"Reflector visibility must remain an inspectable daemon-owned source for Eve and reconnect" ) ;
}
2026-07-17 02:28:38 +01:00
private static void SensorPingIsActorScopedEnergyGatedAndReconnectable ( )
{
var sensorItem = CatalogItem ( "sensor-ping-array" , SensorPayload (
sensitivity : 0.01 ,
pingBoost : 1 ,
pingEnergy : 5 ,
pingVisibility : 4 ,
pingRange : 200 ,
pingCooldown : 1 ,
pingDuration : 1 ,
pingRadiusExponent : 1 ) ) ;
var capacitorItem = CatalogItem ( "sensor-ping-capacitor" , CapacitorPayload ( 10 , 1 ) ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ sensorItem , capacitorItem ] , [ ] , [ ] ) ;
static AetheriaRuntimeEntitySnapshotCommit Observer ( int index , string sensorKey , string capacitorKey )
{
var entity = Entity ( index , 0 , "player" ) ;
entity . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = sensorKey , Quality = 1 , Durability = 1 , Enabled = true } } ,
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = capacitorKey , Quality = 1 , Durability = 1 , Enabled = true } }
] ;
entity . BehaviorStates =
[
new AetheriaRuntimeBehaviorStateCommit
{
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ,
OwnerIndex = 1 ,
BehaviorIndex = 0 ,
BehaviorKind = "Capacitor" ,
CapacitorCharge = 10 ,
CapacitorCapacity = 10 ,
CapacitorEfficiency = 1
}
] ;
return entity ;
}
var actor = Observer ( 0 , sensorItem . ItemKey , capacitorItem . ItemKey ) ;
var other = Observer ( 1 , sensorItem . ItemKey , capacitorItem . ItemKey ) ;
var target = Entity ( 2 , 40 , "raider" ) ;
target . Visibility = 1 ;
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ actor , other , target ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "sensor-ping-smoke" ,
Zones = [ zone ]
} ;
AetheriaRuntimeSensorSimulation . StepZone (
run , zone , [ actor , other , target ] , [ ] , catalog , 0.25 , 0.5 , 0.1 , 1 ) ;
AetheriaRuntimeSensorSimulation . StepZone (
run ,
zone ,
[actor, other, target] ,
[new AetheriaRuntimeDaemonSensorPingIntent { ActorEntityKey = "zone.0.entity.0" }] ,
catalog ,
0.25 ,
0.5 ,
0.1 ,
2 ) ;
var sensor = actor . BehaviorStates . Single ( state = > state . BehaviorKind = = AetheriaRuntimeBehaviorKinds . Sensor ) ;
var otherSensor = other . BehaviorStates . Single ( state = > state . BehaviorKind = = AetheriaRuntimeBehaviorKinds . Sensor ) ;
Require ( sensor . Pinging & & ! otherSensor . Pinging ,
"sensor ping intent must retain actor identity instead of activating every sensor" ) ;
RequireEqual ( 2 , sensor . PingedEntityCount ,
2026-07-17 02:40:34 +01:00
"expanding ping must persist every crossed target index for reconnect-safe exactly-once boost" ) ;
2026-07-17 02:28:38 +01:00
Require ( sensor . PingedEntityIndices . SequenceEqual ( new [ ] { 1 , 2 } ) ,
2026-07-17 02:40:34 +01:00
"pinged target indices must survive in stable order rather than only an unverifiable count" ) ;
2026-07-17 02:28:38 +01:00
RequireNear ( 5 , actor . BehaviorStates . Single ( state = > state . BehaviorKind = = "Capacitor" ) . CapacitorCharge ,
0.000001 , "accepted ping must consume its authored energy exactly once" ) ;
Require ( actor . Contacts . Single ( contact = > contact . TargetEntityIndex = = 2 ) . Visible ,
"ping boost must cross the daemon-owned detection threshold" ) ;
RequireNear ( 4 , actor . StatGrids . Single ( grid = > grid . Name = = "transient-visibility:sensor:0:0" ) . Values . Single ( ) ,
0.000001 , "ping must publish its authored transient visibility source" ) ;
RequireEqual ( 1 , run . GameEvents . Count ( value = > value . Kind = = "sensor.ping.started" ) ,
"accepted ping must emit one provider-owned start event" ) ;
}
2026-07-17 02:40:34 +01:00
private static void TurretControllerAcquiresAimsAndTriggersExactWeapons ( )
{
var weaponPayload = new AetheriaRuntimeBehaviorPayload (
0 ,
AetheriaRuntimeBehaviorKinds . InstantWeapon ,
0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 10 ) ) ,
new AetheriaRuntimeBehaviorField ( 5 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 200 ) ) ,
2026-07-17 04:09:35 +01:00
new AetheriaRuntimeBehaviorField ( 11 , PerformanceStat ( 7 ) ) ,
2026-07-17 02:40:34 +01:00
new AetheriaRuntimeBehaviorField ( 16 , PerformanceStat ( 100 ) ) ,
new AetheriaRuntimeBehaviorField ( 17 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 19 , PerformanceStat ( 0.1 ) ) ,
new AetheriaRuntimeBehaviorField ( 21 , PerformanceStat ( 100 ) ) ,
new AetheriaRuntimeBehaviorField ( 22 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 23 , PerformanceStat ( 180 ) ) ,
new AetheriaRuntimeBehaviorField ( 24 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 25 , PerformanceStat ( 1 ) )
] ) ;
2026-07-17 04:09:35 +01:00
var weaponItem = WearableWeaponCatalogItem ( "turret-smoke-weapon" , weaponPayload ) ;
2026-07-17 02:40:34 +01:00
var controllerItem = CatalogItem (
"turret-smoke-controller" ,
2026-07-17 03:40:58 +01:00
new AetheriaRuntimeBehaviorPayload ( 0 , "EnergyDraw" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 5 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , BoolValue ( false ) )
] ) ,
new AetheriaRuntimeBehaviorPayload ( 1 , AetheriaRuntimeBehaviorKinds . TurretController , 0 , [ ] ) ) ;
var capacitorItem = CatalogItem ( "turret-smoke-capacitor" , CapacitorPayload ( 20 , 1 ) ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ controllerItem , weaponItem , capacitorItem ] , [ ] , [ ] ) ;
2026-07-17 02:40:34 +01:00
var uncontrolled = Entity ( 0 , 0 , "raider" ) ;
uncontrolled . DirectionX = 1 ;
uncontrolled . WeaponGroups = [ new [ ] { 0 } ] ;
uncontrolled . TargetEntityIndex = 1 ;
uncontrolled . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
2026-07-17 04:09:35 +01:00
{ ItemKey = weaponItem . ItemKey , Quality = 0 , Durability = 1 , Enabled = true }
2026-07-17 02:40:34 +01:00
} ] ;
uncontrolled . Contacts = [ new AetheriaRuntimeEntityContactCommit
{ TargetEntityIndex = 1 , InfoGathered = 1 , Visible = true , Hostile = true } ] ;
var uncontrolledTarget = Entity ( 1 , 100 , "player" ) ;
var uncontrolledZone = new AetheriaRuntimeZoneSnapshotCommit
{ ZoneIndex = 0 , Entities = [ uncontrolled , uncontrolledTarget ] } ;
var uncontrolledRun = new AetheriaRuntimeRunCheckpointCommit
{ RunId = "uncontrolled-hostile-smoke" , Zones = [ uncontrolledZone ] } ;
using ( var physics = NewPhysics ( ) )
{
for ( var frame = 0 ; frame < 3 ; frame + + )
AetheriaRuntimeDaemonSimulation . Step (
uncontrolledRun ,
new AetheriaRuntimeDaemonIntentState ( ) ,
0.1 ,
new AetheriaRuntimeDaemonSimulationSettings ( ) ,
physics ,
catalog ,
frame ,
frame * 0.1 ) ;
}
RequireEqual ( 0 , uncontrolledRun . ShotReceipts . Count ,
"non-player entities without a controller or command must not inherit the removed group-zero fire authority" ) ;
var turret = Entity ( 0 , 0 , "player" ) ;
turret . Kind = "station" ;
turret . DirectionX = 1 ;
turret . DirectionY = 0 ;
turret . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = controllerItem . ItemKey , Quality = 1 , Durability = 1 , Enabled = true }
} ,
new AetheriaRuntimeLoadoutItemSlotCommit
{
Rotation = "None" ,
Item = new AetheriaRuntimeLoadoutItemCommit
2026-07-17 04:09:35 +01:00
{ ItemKey = weaponItem . ItemKey , Quality = 0 , Durability = 1 , Enabled = true }
2026-07-17 02:40:34 +01:00
} ,
new AetheriaRuntimeLoadoutItemSlotCommit
{
Rotation = "Half" ,
Item = new AetheriaRuntimeLoadoutItemCommit
2026-07-17 04:09:35 +01:00
{ ItemKey = weaponItem . ItemKey , Quality = 0 , Durability = 1 , Enabled = true }
2026-07-17 03:40:58 +01:00
} ,
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = capacitorItem . ItemKey , Quality = 1 , Durability = 1 , Enabled = true }
2026-07-17 02:40:34 +01:00
}
] ;
turret . WeaponGroups = [ new [ ] { 1 , 2 } ] ;
turret . Contacts = [ new AetheriaRuntimeEntityContactCommit
{ TargetEntityIndex = 1 , InfoGathered = 1 , Visible = true , Hostile = true } ] ;
var target = Entity ( 1 , 100 , "raider" ) ;
target . VelocityY = 5 ;
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ turret , target ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit { RunId = "turret-controller-smoke" , Zones = [ zone ] } ;
using ( var physics = NewPhysics ( ) )
{
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
new AetheriaRuntimeDaemonSimulationSettings ( ) , physics , catalog , 0 , 0 ) ;
2026-07-17 03:40:58 +01:00
RequireEqual ( - 1 , turret . TargetEntityIndex ,
"an unfunded controller must remain unreachable behind its authored EnergyDraw gate" ) ;
RequireEqual ( 0 , run . ShotReceipts . Count ,
"an unfunded controller must not aim or trigger weapons behind the behavior chain" ) ;
var capacitor = turret . BehaviorStates . Single ( state = > state . BehaviorKind = = "Capacitor" ) ;
capacitor . CapacitorCharge = 20 ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
new AetheriaRuntimeDaemonSimulationSettings ( ) , physics , catalog , 1 , 0.1 ) ;
2026-07-17 02:40:34 +01:00
RequireEqual ( target . EntityIndex , turret . TargetEntityIndex ,
"an idle turret controller must acquire the first visible hostile ship without firing on the acquisition tick" ) ;
RequireEqual ( 0 , run . ShotReceipts . Count ,
"target acquisition must not smuggle an extra trigger into the same fossil controller tick" ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
2026-07-17 03:40:58 +01:00
new AetheriaRuntimeDaemonSimulationSettings ( ) , physics , catalog , 2 , 0.2 ) ;
2026-07-17 02:40:34 +01:00
}
var controllerState = turret . BehaviorStates . Single ( state = >
state . BehaviorKind = = AetheriaRuntimeBehaviorKinds . TurretController ) ;
RequireEqual ( 2 , controllerState . TurretControllerWeaponCount ,
"turret controller initialization must publish its exact operational weapon count" ) ;
Require ( controllerState . TurretControllerPredictShots & &
Math . Abs ( controllerState . TurretControllerShotSpeed - 100 ) < 0.000001 & &
turret . LookDirectionY > 0 ,
"projectile velocity must enable the fossil first-order intercept aim and persist its controller state" ) ;
Require ( run . ShotReceipts . Count > 0 & & run . ShotReceipts . All ( receipt = > receipt . WeaponOwnerIndex = = 1 ) ,
"turret controller must trigger only the exact in-range aligned weapon behavior, not its group or reversed neighbor" ) ;
2026-07-17 04:09:35 +01:00
RequireNear ( 7 , turret . StatGrids . Single ( grid = >
grid . Name = = "transient-visibility:weapon:equipment:1:0" ) . Values . Single ( ) , 0.000001 ,
"turret-triggered fire must publish the selected weapon's authored visibility through the shared shot transaction" ) ;
Require ( turret . Equipment [ 1 ] . Item ! . Durability < 1 & &
Math . Abs ( turret . Equipment [ 2 ] . Item ! . Durability - 1 ) < 0.000001 ,
"turret-triggered fire must wear only the exact weapon that committed a shot" ) ;
2026-07-17 02:40:34 +01:00
}
2026-07-17 00:17:12 +01:00
private static void DockingUsesRealBaysAndFossilUndockRules ( )
{
var catalog = new AetheriaRuntimeCatalogSnapshot (
[
CatalogItem ( "dock-cockpit" , new AetheriaRuntimeBehaviorPayload ( 0 , "Cockpit" , 0 , [ ] ) ) ,
CatalogItem ( "dock-thruster" , new AetheriaRuntimeBehaviorPayload ( 0 , "Thruster" , 0 , [ ] ) ) ,
CatalogItem ( "dock-drive" , new AetheriaRuntimeBehaviorPayload ( 0 , "AetherDrive" , 0 , [ ] ) ) ,
CatalogItem ( "dock-reactor" , new AetheriaRuntimeBehaviorPayload ( 0 , "Reactor" , 0 , [ ] ) )
] , [ ] , [ ] ) ;
var context = new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ;
2026-07-17 06:14:41 +01:00
var physicsShip = Entity ( 0 , 24 , "player" ) ;
var physicsStation = Entity ( 1 , 0 , "player" ) ;
physicsStation . Kind = "station" ;
physicsStation . DockingBays =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "dock-bay" , Quantity = 1 }
}
] ;
physicsStation . DockingBayAssignments = [ - 1 ] ;
physicsStation . DockingBayContents = [ Cargo ( ) ] ;
var physicsZone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ physicsShip , physicsStation ]
} ;
var physicsStep = NewPhysics ( ) . Step (
"dock-collision-exclusion-smoke" ,
1 ,
0 ,
physicsZone ,
physicsZone . Entities ,
0.1 ) ;
var steppedShip = physicsStep . Bodies . Single ( body = > body . EntityIndex = = physicsShip . EntityIndex ) ;
RequireNear ( 24 , steppedShip . PositionX , 0.000001 ,
"Ymir must not invent ship/station collision separation that pushes the fossil docking radius out of reach" ) ;
physicsShip . PositionX = steppedShip . PositionX ;
physicsShip . PositionZ = steppedShip . PositionZ ;
var physicsRun = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "dock-collision-exclusion-smoke" ,
CurrentZoneIndex = 0 ,
Zones = [ physicsZone ]
} ;
physicsRun . CurrentEntityKey = physicsRun . EntityRecordKey ( 0 , physicsShip . EntityIndex ) ;
var physicsDock = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . DockNearest ,
"pilot" ,
physicsRun . RunId ,
1 ,
physicsRun . CurrentEntityKey ) ;
var physicsDockResult = AetheriaRuntimeDaemonOperations . Execute ( physicsRun , [ physicsDock ] , context ) ;
Require ( physicsDockResult . AppliedCommandIds . Contains ( physicsDock . CommandId , StringComparer . Ordinal ) & &
physicsStation . DockingBayAssignments . Single ( ) = = physicsShip . EntityIndex ,
"the daemon must still accept docking after Ymir advances the overlapping ship/station bodies: " +
string . Join ( "," , physicsDockResult . RejectedCommandReasons . Values ) ) ;
2026-07-17 00:17:12 +01:00
static AetheriaRuntimeEntitySnapshotCommit DockTarget ( int index , double x , bool hasBay )
{
var target = Entity ( index , x , "station" ) ;
target . PositionZ = 0 ;
if ( hasBay )
{
target . DockingBays = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "dock-bay" }
} ] ;
target . DockingBayAssignments = [ - 1 ] ;
target . DockingBayContents = [ Cargo ( ) ] ;
}
return target ;
}
var actor = Entity ( 0 , 0 , "player" ) ;
2026-07-17 04:00:20 +01:00
actor . WeaponGroups = [ new [ ] { 0 } ] ;
actor . ActiveWeaponGroups = [ true ] ;
actor . WeaponStates = [ new AetheriaRuntimeWeaponStateCommit
{
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ,
OwnerIndex = 0 ,
BehaviorIndex = 0 ,
BehaviorKind = AetheriaRuntimeBehaviorKinds . ChargedWeapon ,
Firing = true ,
TriggerPending = true ,
BurstRemaining = 2 ,
Charging = true ,
Charged = true ,
Charge = 1 ,
ChargeHoldSeconds = 3 ,
ChargeRiskChecks = 2 ,
ChargeMalfunctionRisk = 0.5 ,
LockTargetEntityIndex = 4 ,
LockProgress = 1
} ] ;
2026-07-17 00:17:12 +01:00
var ineligible = DockTarget ( 1 , 5 , false ) ;
var outOfRange = DockTarget ( 2 , 30 , true ) ;
var firstEligible = DockTarget ( 3 , 20 , true ) ;
var nearerButLater = DockTarget ( 4 , 10 , true ) ;
var selectionRun = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "dock-selection-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ actor , ineligible , outOfRange , firstEligible , nearerButLater ]
} ]
} ;
var dock = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . DockNearest ,
"pilot" ,
"dock-selection-smoke" ,
0 ,
selectionRun . CurrentEntityKey ) ;
dock . ScalarValue = 100 ;
var dockResult = AetheriaRuntimeDaemonOperations . Execute ( selectionRun , [ dock ] , context ) ;
RequireEqual ( 1 , dockResult . AppliedCommandIds . Count ,
"DockNearest must accept the first entity with a real empty bay inside the fossil radius" ) ;
RequireEqual ( actor . EntityIndex , firstEligible . DockingBayAssignments . Single ( ) ,
"docking must use the first eligible entity in stable zone order instead of the closest entity" ) ;
RequireEqual ( - 1 , nearerButLater . DockingBayAssignments . Single ( ) ,
"a later closer station must not override the fossil first-eligible selection" ) ;
RequireEqual ( 0 , ineligible . DockingBayAssignments . Count ,
"docking must not manufacture a bay assignment on an entity with no docking-bay equipment" ) ;
RequireEqual ( - 1 , outOfRange . DockingBayAssignments . Single ( ) ,
"a client scalar must not widen the daemon-owned fossil docking radius" ) ;
2026-07-17 04:31:47 +01:00
var dockedEvent = selectionRun . GameEvents . Single ( value = > value . Kind = = "ship.docked" ) ;
Require ( dockedEvent . SourceEntityIndex = = actor . EntityIndex & &
dockedEvent . TargetEntityIndex = = firstEligible . EntityIndex & &
dockedEvent . ScalarValue = = 0 & & dockedEvent . SubjectKey = = selectionRun . CurrentEntityKey ,
"accepted docking must publish one retained actor/parent/bay transition fact" ) ;
2026-07-17 04:00:20 +01:00
var disarmed = actor . WeaponStates . Single ( ) ;
RequireEqual ( 0 , actor . ActiveWeaponGroups . Count ,
"docking must clear the daemon-owned held weapon-group latch" ) ;
Require ( ! disarmed . Firing & & ! disarmed . TriggerPending & & disarmed . BurstRemaining = = 0 & &
! disarmed . Charging & & ! disarmed . Charged & & disarmed . Charge = = 0 & &
disarmed . LockTargetEntityIndex < 0 & & disarmed . LockProgress = = 0 ,
"docking must cancel every transient weapon lifecycle before the ship enters its bay" ) ;
var dockedFire = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . SetWeaponGroupActive ,
"pilot" ,
selectionRun . RunId ,
1 ,
selectionRun . CurrentEntityKey ) ;
dockedFire . CommandId = "docked-fire-forbidden" ;
dockedFire . WeaponGroup = 0 ;
dockedFire . ScalarValue = 1 ;
var dockedFireResult = AetheriaRuntimeDaemonOperations . Execute ( selectionRun , [ dockedFire ] , context ) ;
Require ( dockedFireResult . RejectedCommandIds . Contains ( dockedFire . CommandId ) & &
dockedFireResult . Intents . WeaponGroups . Count = = 0 & & actor . ActiveWeaponGroups . Count = = 0 ,
"a docked actor must reject held-fire commands without rearming daemon state" ) ;
2026-07-17 00:17:12 +01:00
AetheriaRuntimeRunCheckpointCommit DockedRun (
IReadOnlyList < string > itemKeys ,
bool bayHasCargo = false )
{
var ship = Entity ( 0 , 7 , "player" ) ;
ship . PositionZ = 9 ;
ship . VelocityX = 3 ;
ship . VelocityY = - 4 ;
ship . DirectionX = 0.6 ;
ship . DirectionY = 0.8 ;
ship . Equipment = itemKeys . Select ( itemKey = > new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = itemKey ,
Durability = 1 ,
Enabled = true
}
} ) . ToArray ( ) ;
var station = DockTarget ( 1 , 7 , true ) ;
station . PositionZ = 9 ;
station . ChildEntityIndices = [ 0 ] ;
station . DockingBayAssignments = [ 0 ] ;
station . DockingBayContents = [ bayHasCargo
? Cargo ( ( "forgotten-cargo" , 1 , 0 , 0 ) )
: Cargo ( ) ] ;
return new AetheriaRuntimeRunCheckpointCommit
{
RunId = "undock-parity-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship , station ] } ]
} ;
}
AetheriaRuntimeDaemonOperationResult RejectUndock (
IReadOnlyList < string > itemKeys ,
string expectedReason ,
bool bayHasCargo = false )
{
var run = DockedRun ( itemKeys , bayHasCargo ) ;
var command = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . Undock ,
"pilot" ,
"undock-parity-smoke" ,
0 ,
run . CurrentEntityKey ) ;
command . CommandId = $"undock:{expectedReason}" ;
var result = AetheriaRuntimeDaemonOperations . Execute ( run , [ command ] , context ) ;
RequireEqual ( expectedReason , result . RejectedCommandReasons [ command . CommandId ] ,
"undock rejection must retain the exact daemon-owned fossil reason" ) ;
Require ( run . Zones [ 0 ] . Entities [ 1 ] . DockingBayAssignments . Contains ( 0 ) ,
"a rejected undock must leave parentage and bay assignment untouched" ) ;
2026-07-17 04:31:47 +01:00
Require ( ! run . GameEvents . Any ( value = > value . Kind = = "ship.undocked" ) ,
"a rejected undock must not publish a false presentation transition" ) ;
2026-07-17 00:17:12 +01:00
return result ;
}
RejectUndock ( [ "dock-thruster" , "dock-reactor" ] ,
AetheriaRuntimeDaemonRejectionReasons . MissingCockpit ) ;
RejectUndock ( [ "dock-cockpit" , "dock-reactor" ] ,
AetheriaRuntimeDaemonRejectionReasons . MissingPropulsion ) ;
RejectUndock ( [ "dock-cockpit" , "dock-thruster" ] ,
AetheriaRuntimeDaemonRejectionReasons . MissingReactor ) ;
var cargoRejected = RejectUndock (
["dock-cockpit", "dock-thruster", "dock-reactor"] ,
AetheriaRuntimeDaemonRejectionReasons . DockingBayCargoNotEmpty ,
bayHasCargo : true ) ;
var cargoFrame = AetheriaRuntimeDaemonFrameDocument . Create (
cargoRejected . Run , "daemon" , "session" , 4 , 0.08 , 0.02 ) ;
cargoFrame . RejectedCommandIds = cargoRejected . RejectedCommandIds ;
cargoFrame . RejectedCommandReasons = cargoRejected . RejectedCommandReasons ;
var cargoCommand = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . Undock ,
"pilot" ,
"undock-parity-smoke" ,
0 ,
cargoRejected . Run . CurrentEntityKey ) ;
cargoCommand . CommandId = "undock:docking-bay-cargo-not-empty" ;
var fact = AetheriaRuntimeCommittedCommandFactDocument . FromRejectedCommand (
cargoFrame , cargoCommand , "aetheria.local" ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . DockingBayCargoNotEmpty , fact . RejectionReason ,
"the committed command fact must carry the daemon-owned undock rejection reason" ) ;
var receipt = AetheriaRuntimeDaemonReceiptProjector . Project (
fact , AetheriaRuntimeDaemonGameSurfaceBuilder . SurfaceId ) ;
Require ( receipt . State = = "denied" & &
receipt . Message . Contains ( AetheriaRuntimeDaemonRejectionReasons . DockingBayCargoNotEmpty ,
StringComparison . Ordinal ) ,
"the generic Eve receipt must expose the exact rejection reason without client reconstruction" ) ;
var successRun = DockedRun ( [ "dock-cockpit" , "dock-drive" , "dock-reactor" ] ) ;
var successShip = successRun . Zones [ 0 ] . Entities [ 0 ] ;
var poseBefore = (
successShip . PositionX ,
successShip . PositionZ ,
successShip . VelocityX ,
successShip . VelocityY ,
successShip . DirectionX ,
successShip . DirectionY ) ;
var undock = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . Undock ,
"pilot" ,
"undock-parity-smoke" ,
0 ,
successRun . CurrentEntityKey ) ;
var undockResult = AetheriaRuntimeDaemonOperations . Execute ( successRun , [ undock ] , context ) ;
RequireEqual ( 1 , undockResult . AppliedCommandIds . Count ,
"AetherDrive must satisfy the fossil propulsion alternative for rare compatible ships" ) ;
RequireEqual ( poseBefore , (
successShip . PositionX ,
successShip . PositionZ ,
successShip . VelocityX ,
successShip . VelocityY ,
successShip . DirectionX ,
successShip . DirectionY ) ,
"undocking must preserve the ship pose, velocity, and direction instead of applying an invented launch" ) ;
Require ( ! successRun . Zones [ 0 ] . Entities [ 1 ] . DockingBayAssignments . Contains ( 0 ) ,
"successful undocking must release the exact occupied bay" ) ;
2026-07-17 04:31:47 +01:00
var undockedEvent = successRun . GameEvents . Single ( value = > value . Kind = = "ship.undocked" ) ;
Require ( undockedEvent . SourceEntityIndex = = successShip . EntityIndex & &
undockedEvent . TargetEntityIndex = = successRun . Zones [ 0 ] . Entities [ 1 ] . EntityIndex & &
undockedEvent . ScalarValue = = 0 ,
"accepted undocking must retain the released parent and bay after state removal" ) ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = successRun } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ,
catalog : catalog ) ;
Require ( Flatten ( surface . Surface . Root ) . Any ( node = > node . Kind = = "feedback.event" & &
node . Props [ "eventKind" ] = = "ship.undocked" & &
node . Props [ "sourceEntityIndex" ] = = "0" & & node . Props [ "targetEntityIndex" ] = = "1" & &
node . Props [ "scalarValue" ] = = "0" ) ,
"generic Eve feedback must expose authoritative docking chronology and bay identity" ) ;
2026-07-17 00:17:12 +01:00
}
2026-07-17 04:00:20 +01:00
private static void DockedEntitiesCannotAttackOrBeTargeted ( )
{
var weaponPayload = new AetheriaRuntimeBehaviorPayload (
0 ,
AetheriaRuntimeBehaviorKinds . ConstantWeapon ,
0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 10 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 200 ) ) ,
new AetheriaRuntimeBehaviorField ( 9 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 10 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 11 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 13 , Number ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 14 , Number ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 17 , Number ( 1 ) )
] ) ;
var weapon = CatalogItem ( "docked-combat-weapon" , weaponPayload ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ weapon ] , [ ] , [ ] ) ;
static AetheriaRuntimeEntitySnapshotCommit ArmedShip ( int index , double x , string faction , string itemKey )
{
var ship = Entity ( index , x , faction ) ;
ship . WeaponGroups = [ new [ ] { 0 } ] ;
ship . ActiveWeaponGroups = [ true ] ;
ship . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = itemKey , Quality = 1 , Durability = 1 , Enabled = true }
} ] ;
return ship ;
}
var dockedAttacker = ArmedShip ( 0 , 0 , "player" , weapon . ItemKey ) ;
dockedAttacker . TargetEntityIndex = 2 ;
var station = Entity ( 1 , 0 , "player" ) ;
station . ChildEntityIndices = [ 0 ] ;
station . DockingBayAssignments = [ 0 ] ;
var exposedTarget = Entity ( 2 , 50 , "raider" ) ;
var attackerRun = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "docked-attacker-smoke" ,
CurrentZoneIndex = 0 ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit
{ ZoneIndex = 0 , Entities = [ dockedAttacker , station , exposedTarget ] } ]
} ;
var forgedIntent = new AetheriaRuntimeDaemonIntentState ( ) ;
forgedIntent . WeaponGroups . Add ( new AetheriaRuntimeDaemonWeaponGroupIntent
{ ActorEntityKey = "zone.0.entity.0" , WeaponGroup = 0 , Fire = true , Active = true } ) ;
AetheriaRuntimeDaemonSimulation . Step (
attackerRun , forgedIntent , 0.1 , new AetheriaRuntimeDaemonSimulationSettings ( ) ,
NewPhysics ( ) , catalog , 0 , 0 ) ;
RequireEqual ( 0 , attackerRun . ShotReceipts . Count ,
"combat must subtract docked attackers even when stale state and a forged pulse both request fire" ) ;
RequireNear ( 100 , Stat ( exposedTarget , "hull" ) , 0.000001 ,
"a docked child must not damage an exposed world entity" ) ;
var exposedAttacker = ArmedShip ( 0 , 0 , "player" , weapon . ItemKey ) ;
exposedAttacker . TargetEntityIndex = 1 ;
var dockedTarget = Entity ( 1 , 50 , "raider" ) ;
var hostileStation = Entity ( 2 , 50 , "raider" ) ;
hostileStation . ChildEntityIndices = [ 1 ] ;
hostileStation . DockingBayAssignments = [ 1 ] ;
var targetRun = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "docked-target-smoke" ,
CurrentZoneIndex = 0 ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit
{ ZoneIndex = 0 , Entities = [ exposedAttacker , dockedTarget , hostileStation ] } ]
} ;
AetheriaRuntimeDaemonSimulation . Step (
targetRun , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
new AetheriaRuntimeDaemonSimulationSettings ( ) , NewPhysics ( ) , catalog , 0 , 0 ) ;
RequireEqual ( 0 , targetRun . ShotReceipts . Count ,
"combat target lookup must subtract docked children from world participants" ) ;
RequireNear ( 100 , Stat ( dockedTarget , "hull" ) , 0.000001 ,
"a docked child must not receive ordinary world combat damage through stale targeting" ) ;
}
2026-07-17 00:46:58 +01:00
private static void RefitIsAtomicAndUsesTypedPlacement ( )
{
static AetheriaRuntimeCatalogItem ShapedItem (
string key ,
string category ,
string hardpointType ,
int width ,
int height ,
params ( int X , int Y ) [ ] cells )
{
var item = CatalogItem ( key ) ;
item . Category = category ;
item . HardpointType = hardpointType ;
item . ShapeWidth = width ;
item . ShapeHeight = height ;
item . OccupiedCells = cells . Length ;
item . ShapeCells = cells . Select ( cell = > new AetheriaRuntimeShapeCell ( cell . X , cell . Y ) ) . ToArray ( ) ;
return item ;
}
var hull = HullCatalogItem ( "refit-hull" , 4 , 3 , 1 ) ;
hull . Hardpoints =
[
new AetheriaRuntimeHardpoint (
"Weapon" ,
2 ,
0 ,
1 ,
2 ,
2 ,
[new AetheriaRuntimeShapeCell(0, 0), new AetheriaRuntimeShapeCell(0, 1)] ,
"" ,
"Clockwise" ,
0 )
] ;
var weapon = ShapedItem (
"refit-weapon" ,
AetheriaRuntimeItemCategories . Weapon ,
"Weapon" ,
2 ,
1 ,
( 0 , 0 ) ,
( 1 , 0 ) ) ;
var blocker = ShapedItem ( "refit-blocker" , AetheriaRuntimeItemCategories . Gear , "" , 1 , 1 , ( 0 , 0 ) ) ;
var cargoBay = ShapedItem ( "refit-cargo-bay" , AetheriaRuntimeItemCategories . CargoBay , "" , 1 , 1 , ( 0 , 0 ) ) ;
cargoBay . InteriorShapeWidth = 4 ;
cargoBay . InteriorShapeHeight = 3 ;
cargoBay . InteriorOccupiedCells = 12 ;
cargoBay . InteriorShapeCells = Enumerable . Range ( 0 , 3 )
. SelectMany ( y = > Enumerable . Range ( 0 , 4 ) . Select ( x = > new AetheriaRuntimeShapeCell ( x , y ) ) )
. ToArray ( ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , weapon , blocker , cargoBay ] , [ ] , [ ] ) ;
var station = Entity ( 0 , 0 , "player" ) ;
station . Kind = "station" ;
station . CargoBays =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
}
] ;
station . CargoContents = [ new AetheriaRuntimeCargoBayLoadoutCommit ( ) ] ;
station . DockingBays =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "station-refit-dock" , Quantity = 1 }
}
] ;
station . DockingBayAssignments = [ 1 ] ;
station . DockingBayContents = [ new AetheriaRuntimeCargoBayLoadoutCommit ( ) ] ;
station . ChildEntityIndices = [ 1 ] ;
var ship = Entity ( 1 , 0 , "player" ) ;
ship . HullItemKey = hull . ItemKey ;
ship . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 0 ,
Y = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = blocker . ItemKey ,
Quality = 0.8 ,
Durability = 0.7 ,
Quantity = 1 ,
Enabled = false ,
OverrideShutdown = true ,
Temperature = 321
}
}
] ;
ship . CargoBays =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 3 ,
Y = 2 ,
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
}
] ;
ship . CargoContents =
[
new AetheriaRuntimeCargoBayLoadoutCommit
{
Items =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 0 ,
Y = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = weapon . ItemKey ,
Quality = 0.9 ,
Durability = 0.6 ,
Quantity = 1 ,
Enabled = true ,
Temperature = 444
}
} ,
new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 1 ,
Y = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = blocker . ItemKey , Quantity = 1 }
} ,
new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 2 ,
Y = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
}
]
}
] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "refit-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.1" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ station , ship ] } ]
} ;
var context = new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ;
AetheriaRuntimeDaemonCommandDocument Equip (
string id ,
string sourceKind ,
int sourceIndex ,
string itemKey ,
int sourceX ,
int sourceY ,
int destinationX ,
int destinationY )
{
var command = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . EquipItem ,
"pilot" ,
run . RunId ,
1 ,
run . CurrentEntityKey ) ;
command . CommandId = id ;
command . TextValue = itemKey ;
command . EquipmentTransfer = new AetheriaRuntimeEquipmentTransferCommand
{
SourceKind = sourceKind ,
OriginEntityKey = run . CurrentEntityKey ,
OriginIndex = sourceIndex ,
SourceX = sourceX ,
SourceY = sourceY ,
DestinationEntityKey = run . CurrentEntityKey ,
DestinationX = destinationX ,
DestinationY = destinationY ,
HasDestinationPosition = true
} ;
return command ;
}
var equipWeapon = AetheriaRuntimeDaemonOperations . Execute (
run ,
[Equip("refit-weapon", AetheriaRuntimeRefitSourceKinds.Cargo, 0, weapon.ItemKey, 0, 0, 2, 0)] ,
context ) ;
Require ( equipWeapon . AppliedCommandIds . Contains ( "refit-weapon" ) ,
"a docked cargo weapon must equip through the daemon transaction" ) ;
var equippedWeapon = ship . Equipment . Single ( slot = > slot . Item . ItemKey = = weapon . ItemKey ) ;
RequireEqual ( "Clockwise" , equippedWeapon . Rotation ,
"hardpoint equipment must inherit the authored hardpoint rotation" ) ;
RequireNear ( 0.9 , equippedWeapon . Item . Quality , 0.000001 ,
"refit must preserve the exact item instance quality" ) ;
RequireNear ( 444 , equippedWeapon . Item . Temperature , 0.000001 ,
"refit must preserve the exact item instance temperature" ) ;
var rejectedSource = ship . CargoContents [ 0 ] . Items . Single ( slot = > slot . Item . ItemKey = = blocker . ItemKey ) ;
var rejectedBefore = (
Count : ship . CargoContents [ 0 ] . Items . Count ,
X : rejectedSource . X ,
Y : rejectedSource . Y ,
Quality : rejectedSource . Item . Quality ,
Durability : rejectedSource . Item . Durability ,
Temperature : rejectedSource . Item . Temperature ) ;
var overlap = AetheriaRuntimeDaemonOperations . Execute (
run ,
[Equip("refit-overlap", AetheriaRuntimeRefitSourceKinds.Cargo, 0, blocker.ItemKey, 1, 0, 0, 0)] ,
context ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . RefitNoFit ,
overlap . RejectedCommandReasons [ "refit-overlap" ] ,
"occupied interior cells must reject with the daemon-owned fit reason" ) ;
var rejectedAfter = ship . CargoContents [ 0 ] . Items . Single ( slot = > slot . Item . ItemKey = = blocker . ItemKey ) ;
RequireEqual ( rejectedBefore . Count , ship . CargoContents [ 0 ] . Items . Count ,
"rejected refit must not remove the source item" ) ;
Require ( rejectedBefore . X = = rejectedAfter . X & & rejectedBefore . Y = = rejectedAfter . Y & &
rejectedBefore . Quality = = rejectedAfter . Item . Quality & &
rejectedBefore . Durability = = rejectedAfter . Item . Durability & &
rejectedBefore . Temperature = = rejectedAfter . Item . Temperature ,
"rejected refit must preserve every source instance field" ) ;
var equipBay = AetheriaRuntimeDaemonOperations . Execute (
run ,
[Equip("refit-bay", AetheriaRuntimeRefitSourceKinds.Cargo, 0, cargoBay.ItemKey, 2, 0, 1, 2)] ,
context ) ;
Require ( equipBay . AppliedCommandIds . Contains ( "refit-bay" ) & & ship . CargoBays . Count = = 2 & & ship . CargoContents . Count = = 2 ,
"catalog cargo-bay category must route into aligned typed bay and contents collections" ) ;
ship . CargoContents [ 1 ] . Items =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = blocker . ItemKey , Quantity = 1 }
}
] ;
var storeBay = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . StoreItem ,
"pilot" ,
run . RunId ,
1 ,
run . CurrentEntityKey ) ;
storeBay . CommandId = "refit-nonempty-bay" ;
storeBay . TextValue = cargoBay . ItemKey ;
storeBay . StoreItem = new AetheriaRuntimeStoreItemCommand
{
SourceKind = AetheriaRuntimeRefitSourceKinds . CargoBay ,
OriginEntityKey = run . CurrentEntityKey ,
SourceEquipmentIndex = 1 ,
DestinationEntityKey = "zone.0.entity.0" ,
DestinationCargoIndex = 0 ,
DestinationX = 0 ,
DestinationY = 0 ,
HasDestinationPosition = true
} ;
var nonempty = AetheriaRuntimeDaemonOperations . Execute ( run , [ storeBay ] , context ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . RefitBayNotEmpty ,
nonempty . RejectedCommandReasons [ storeBay . CommandId ] ,
"a nonempty cargo bay must reject unequip before any mutation" ) ;
RequireEqual ( 2 , ship . CargoBays . Count ,
"nonempty bay rejection must preserve the installed bay" ) ;
var frame = AetheriaRuntimeDaemonFrameDocument . Create ( run , "daemon" , "session" , 8 , 0.16 , 0.02 ) ;
frame . RejectedCommandIds = nonempty . RejectedCommandIds ;
frame . RejectedCommandReasons = nonempty . RejectedCommandReasons ;
var fact = AetheriaRuntimeCommittedCommandFactDocument . FromRejectedCommand ( frame , storeBay , "aetheria.local" ) ;
var receipt = AetheriaRuntimeDaemonReceiptProjector . Project (
fact ,
AetheriaRuntimeDaemonGameSurfaceBuilder . SurfaceId ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . RefitBayNotEmpty , fact . RejectionReason ,
"refit rejection reason must survive the committed command fact" ) ;
Require ( receipt . State = = "denied" & &
receipt . Message . Contains ( AetheriaRuntimeDaemonRejectionReasons . RefitBayNotEmpty , StringComparison . Ordinal ) ,
"generic Eve receipt must expose the exact refit rejection reason" ) ;
station . DockingBayAssignments = [ - 1 ] ;
station . ChildEntityIndices = [ ] ;
var deployed = AetheriaRuntimeDaemonOperations . Execute (
run ,
[Equip("refit-deployed", AetheriaRuntimeRefitSourceKinds.Equipment, 0, blocker.ItemKey, int.MinValue, int.MinValue, 1, 1)] ,
context ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . RefitRequiresDocked ,
deployed . RejectedCommandReasons [ "refit-deployed" ] ,
"deployed ships must not refit even when the requested placement would fit" ) ;
Require ( ship . Equipment . Any ( slot = > slot . Item . ItemKey = = blocker . ItemKey ) ,
"deployed refit rejection must preserve installed equipment" ) ;
}
2026-07-17 00:56:01 +01:00
private static void CargoTransferUsesSpatialAtomicTransaction ( )
{
var cargoBay = CatalogItem ( "grid-cargo-bay" ) ;
cargoBay . Category = AetheriaRuntimeItemCategories . CargoBay ;
cargoBay . ShapeWidth = 1 ;
cargoBay . ShapeHeight = 1 ;
cargoBay . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
cargoBay . InteriorShapeWidth = 2 ;
cargoBay . InteriorShapeHeight = 1 ;
cargoBay . InteriorOccupiedCells = 2 ;
cargoBay . InteriorShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) , new AetheriaRuntimeShapeCell ( 1 , 0 ) ] ;
var commodity = CatalogItem ( "grid-commodity" ) ;
commodity . Category = AetheriaRuntimeItemCategories . SimpleCommodity ;
commodity . ShapeWidth = 1 ;
commodity . ShapeHeight = 1 ;
commodity . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
commodity . Stackable = true ;
commodity . MaxStack = 10 ;
var blocker = CatalogItem ( "grid-blocker" ) ;
blocker . ShapeWidth = 1 ;
blocker . ShapeHeight = 1 ;
blocker . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ cargoBay , commodity , blocker ] , [ ] , [ ] ) ;
AetheriaRuntimeEntitySnapshotCommit CargoEntity ( int index , params AetheriaRuntimeLoadoutItemSlotCommit [ ] items )
{
var entity = Entity ( index , 0 , "player" ) ;
entity . CargoBays =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
}
] ;
entity . CargoContents = [ new AetheriaRuntimeCargoBayLoadoutCommit { Items = items } ] ;
return entity ;
}
var source = CargoEntity ( 0 , new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 0 ,
Y = 0 ,
Rotation = "None" ,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = commodity . ItemKey ,
Quantity = 4 ,
Quality = 0.75 ,
Durability = 0.5 ,
Temperature = 333
}
} ) ;
var destination = CargoEntity (
1 ,
new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 0 ,
Y = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = blocker . ItemKey , Quantity = 1 }
} ,
new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 1 ,
Y = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = commodity . ItemKey , Quantity = 8 }
} ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "cargo-grid-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ source , destination ] } ]
} ;
var context = new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ;
AetheriaRuntimeDaemonCommandDocument Transfer ( string id , int quantity , int x , bool positioned = true )
{
var command = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . TransferCargoItem ,
"pilot" ,
run . RunId ,
0 ,
run . CurrentEntityKey ) ;
command . CommandId = id ;
command . TextValue = commodity . ItemKey ;
command . CargoTransfer = new AetheriaRuntimeCargoTransferCommand
{
OriginEntityKey = "zone.0.entity.0" ,
OriginCargoIndex = 0 ,
DestinationEntityKey = "zone.0.entity.1" ,
DestinationCargoIndex = 0 ,
SourceX = 0 ,
SourceY = 0 ,
DestinationX = x ,
DestinationY = 0 ,
HasDestinationPosition = positioned ,
Quantity = quantity
} ;
return command ;
}
var overfill = AetheriaRuntimeDaemonOperations . Execute ( run , [ Transfer ( "cargo-overfill" , 3 , 1 ) ] , context ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . CargoStackLimit ,
overfill . RejectedCommandReasons [ "cargo-overfill" ] ,
"an explicit commodity stack overfill must reject atomically" ) ;
RequireEqual ( 4 , source . CargoContents [ 0 ] . Items . Single ( ) . Item . Quantity ,
"stack-limit rejection must not decrement the source stack" ) ;
RequireEqual ( 8 , destination . CargoContents [ 0 ] . Items . Single ( slot = > slot . Item . ItemKey = = commodity . ItemKey ) . Item . Quantity ,
"stack-limit rejection must not partially fill the destination stack" ) ;
var stacked = AetheriaRuntimeDaemonOperations . Execute ( run , [ Transfer ( "cargo-stack" , 2 , 1 ) ] , context ) ;
Require ( stacked . AppliedCommandIds . Contains ( "cargo-stack" ) ,
"a complete explicit stack merge must commit" ) ;
RequireEqual ( 2 , source . CargoContents [ 0 ] . Items . Single ( ) . Item . Quantity ,
"accepted stack merge must remove exactly the requested source quantity" ) ;
RequireEqual ( 10 , destination . CargoContents [ 0 ] . Items . Single ( slot = > slot . Item . ItemKey = = commodity . ItemKey ) . Item . Quantity ,
"accepted stack merge must fill the destination to the typed maximum" ) ;
var occupied = AetheriaRuntimeDaemonOperations . Execute ( run , [ Transfer ( "cargo-overlap" , 1 , 0 ) ] , context ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . CargoNoFit ,
occupied . RejectedCommandReasons [ "cargo-overlap" ] ,
"an occupied cell containing another item must reject spatial placement" ) ;
RequireEqual ( 2 , source . CargoContents [ 0 ] . Items . Single ( ) . Item . Quantity ,
"spatial rejection must leave the source stack untouched" ) ;
destination . CargoContents [ 0 ] . Items = [ ] ;
var placed = AetheriaRuntimeDaemonOperations . Execute ( run , [ Transfer ( "cargo-place" , 2 , 0 , positioned : false ) ] , context ) ;
Require ( placed . AppliedCommandIds . Contains ( "cargo-place" ) & & source . CargoContents [ 0 ] . Items . Count = = 0 ,
"unpositioned transfer must commit only after finding the first authored interior cell" ) ;
var moved = destination . CargoContents [ 0 ] . Items . Single ( ) ;
Require ( moved . X = = 0 & & moved . Y = = 0 & & moved . Item . Quantity = = 2 ,
"unpositioned cargo placement must use deterministic interior order" ) ;
RequireNear ( 0.75 , moved . Item . Quality , 0.000001 ,
"cargo transfer must preserve source instance quality" ) ;
RequireNear ( 333 , moved . Item . Temperature , 0.000001 ,
"cargo transfer must preserve source instance temperature" ) ;
}
2026-07-15 20:17:05 +01:00
private static void VolumeSurfaceKeepsNativeShaderAbiInAssetVariant ( )
{
var player = Entity ( 0 , 0 , "player" ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "volume-program-ownership-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ player ] } ]
} ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
var volume = Flatten ( surface . Surface . Root ) . Single ( node = > node . Kind = = "field.volume3d" ) ;
2026-07-16 12:27:19 +01:00
var stardust = Flatten ( surface . Surface . Root ) . Single ( node = > node . Kind = = "field.particles3d" ) ;
2026-07-16 02:23:36 +01:00
var gravityField = Flatten ( surface . Surface . Root ) . Single ( node = > node . Kind = = "field.surface2d" ) ;
2026-07-15 20:17:05 +01:00
Require ( volume . Props . Values . All ( value = > value = = null | | ! value . Contains ( "_Nebula" , StringComparison . Ordinal ) ) & &
2026-07-15 22:59:51 +01:00
volume . Props [ "layerBindings" ] . Contains ( "fog.surface_height=surfaceHeight" , StringComparison . Ordinal ) & &
2026-07-16 01:56:29 +01:00
volume . Props [ "layerTargetDescriptors" ] . Contains ( "fog.surface_height=2,2,false,bilinear" , StringComparison . Ordinal ) & &
volume . Props [ "layerTargetDescriptors" ] . Contains ( "fog.tint=0.5,0.5,true,trilinear" , StringComparison . Ordinal ) & &
2026-07-15 21:54:11 +01:00
volume . Props [ "viewportTextureScaleBindings" ] = = "ditherCoordinates=dither" & &
2026-07-16 17:54:00 +01:00
volume . Props [ "viewportAnchor" ] = = stardust . Props [ "viewportAnchor" ] & &
volume . Props [ "span" ] = = stardust . Props [ "span" ] & &
volume . Props [ "cellWorldSize" ] = = stardust . Props [ "cellWorldSize" ] & &
volume . Props [ "gravityTexelsPerCell" ] = = stardust . Props [ "gravityTexelsPerCell" ] & &
volume . Props [ "viewportSnapLayer" ] = = stardust . Props [ "viewportSnapLayer" ] & &
volume . Props [ "viewportSnapTexels" ] = = stardust . Props [ "viewportSnapTexels" ] & &
2026-07-16 01:56:29 +01:00
volume . Props [ "documentFloatBindings" ] = = "simulationTimeSeconds=flowScroll,0.025,0" & &
2026-07-15 21:54:11 +01:00
! volume . Props . ContainsKey ( "vectorParameters" ) ,
2026-07-15 20:17:05 +01:00
"portable Eve volume surfaces must name logical ports rather than Unity shader properties" ) ;
2026-07-16 12:27:19 +01:00
Require ( gravityField . Props [ "minX" ] = = "-768" & &
gravityField . Props [ "minY" ] = = "-768" & &
gravityField . Props [ "maxX" ] = = "768" & &
gravityField . Props [ "maxY" ] = = "768" & &
2026-07-16 02:23:36 +01:00
volume . Props [ "documentRef" ] = = gravityField . Props [ "renderSplatsDocumentId" ] ,
2026-07-16 12:27:19 +01:00
"flight fog rasterization must share the exact 256-by-6 Stardust lattice viewport" ) ;
Require ( stardust . Props [ "documentRef" ] = = gravityField . Props [ "renderSplatsDocumentId" ] & &
stardust . Props [ "computeProgramAssetRef" ] = = "compute.environment.stardust" & &
stardust . Props [ "materialAssetRef" ] = = "material.environment.stardust" & &
stardust . Props [ "span" ] = = "256" & &
stardust . Props [ "threadGroupSize" ] = = "128" & &
stardust . Props [ "particleStrideBytes" ] = = "28" & &
stardust . Props [ "viewportAnchor" ] = = "active-camera.xz" & &
stardust . Props [ "layerBindings" ] = = "fog.surface_height=surfaceHeight;fog.tint=tint" & &
2026-07-16 18:16:39 +01:00
stardust . Props [ "materialAssetTextureBindings" ] = = "texture.environment.volume-dither=dither" & &
stardust . Props [ "materialViewportTextureScaleBindings" ] = = "ditherCoordinates=dither" & &
stardust . Props [ "materialRenderFrameIndexPort" ] = = "frameIndex" & &
2026-07-16 12:27:19 +01:00
stardust . Props [ "cellWorldSize" ] = = "6" & &
stardust . Props [ "gravityTexelsPerCell" ] = = "8" & &
stardust . Props [ "viewportSnapLayer" ] = = "fog.surface_height" & &
stardust . Props [ "viewportSnapTexels" ] = = "8" & &
stardust . Props [ "documentFloatBindings" ] = =
"simulationTimeSeconds=time,1,0;simulationTimeSeconds=flowScroll,0.025,0" & &
stardust . Props [ "documentTimeVectorPort" ] = = "timeVector" & &
stardust . Props [ "floatParameters" ] . Contains (
"period=2;minimumSize=0.25;maximumSize=0.75;spacing=6;ceilingHeight=0;" +
"floorHeight=-10;minHeadroom=25;maxHeadroom=100;heightExponent=3" ,
2026-07-16 12:43:47 +01:00
StringComparison . Ordinal ) & &
! stardust . Props [ "floatParameters" ] . Contains ( "patch" , StringComparison . OrdinalIgnoreCase ) ,
2026-07-16 12:27:19 +01:00
"portable Stardust semantics must preserve the grid/gravity lattice, dispatch, camera snap, time, and particle values exactly" ) ;
2026-07-15 20:17:05 +01:00
var shader = AetheriaRuntimeAssets . ProjectManifest ( null ) . Assets . Single ( asset = >
asset . Ref . AssetKey = = "shader.environment.gravity-fog" ) ;
2026-07-16 01:56:29 +01:00
var postProcess = AetheriaRuntimeAssets . ProjectManifest ( null ) . Assets . Single ( asset = >
asset . Ref . AssetKey = = "profile.environment.flight" ) ;
2026-07-16 12:27:19 +01:00
var stardustCompute = AetheriaRuntimeAssets . ProjectManifest ( null ) . Assets . Single ( asset = >
asset . Ref . AssetKey = = "compute.environment.stardust" ) ;
var stardustMaterial = AetheriaRuntimeAssets . ProjectManifest ( null ) . Assets . Single ( asset = >
asset . Ref . AssetKey = = "material.environment.stardust" ) ;
var stardustColors = AetheriaRuntimeAssets . ProjectManifest ( null ) . Assets . Single ( asset = >
asset . Ref . AssetKey = = "texture.environment.stardust-colors" ) ;
2026-07-16 01:56:29 +01:00
Require ( postProcess . Ref . Kind = = AetheriaRuntimeAssetKinds . VolumeProfile & &
postProcess . Ref . Metadata [ "presentationRole" ] = = "environment.post-process.flight" ,
"provider asset catalog must carry the advertised flight post-process profile variant" ) ;
2026-07-15 20:17:05 +01:00
Require ( shader . Ref . Metadata [ "unity.volume.texturePort.surfaceHeight" ] = = "_NebulaSurfaceHeight" & &
2026-07-16 01:56:29 +01:00
shader . Ref . Metadata [ "unity.volume.matrixPort.cameraToWorld" ] = = "_CamToWorld" & &
2026-07-15 21:09:20 +01:00
shader . Ref . Metadata [ "unity.volume.pass.raymarch" ] = = "0" & &
shader . Ref . Metadata [ "unity.volume.pass.temporal" ] = = "1" & &
shader . Ref . Metadata [ "unity.volume.pass.composite" ] = = "2" & &
shader . Ref . Metadata [ "unity.volume.texturePort.currentSample" ] = = "_UndersampleCloudTex" & &
shader . Ref . Metadata [ "unity.volume.texturePort.history" ] = = "_MainTex" & &
shader . Ref . Metadata [ "unity.volume.matrixPort.previousViewProjection" ] = = "_PrevVP" & &
2026-07-15 23:57:48 +01:00
shader . Ref . Metadata [ "unity.volume.floatPort.resetHistory" ] = = "_ResetHistory" ,
2026-07-15 20:17:05 +01:00
"provider asset metadata must own the concrete Unity volume-program ABI projected into runtime variants" ) ;
2026-07-16 12:27:19 +01:00
Require ( stardustCompute . Ref . Kind = = AetheriaRuntimeAssetKinds . ComputeShader & &
stardustCompute . Ref . Metadata [ "unity.particles.kernel.update" ] = = "UpdateParticles" & &
stardustCompute . Ref . Metadata [ "unity.particles.bufferPort.particles" ] = = "particles" & &
! stardustCompute . Ref . Metadata . ContainsKey ( "unity.particles.texturePort.patch" ) & &
! stardustCompute . Ref . Metadata . ContainsKey ( "unity.particles.texturePort.patchHeight" ) & &
2026-07-16 12:43:47 +01:00
! stardustCompute . Ref . Metadata . ContainsKey ( "unity.particles.floatPort.patchDensity" ) & &
! stardustCompute . Ref . Metadata . ContainsKey ( "unity.particles.floatPort.patchBlend" ) & &
2026-07-16 12:27:19 +01:00
stardustCompute . Ref . Metadata [ "unity.particles.vectorPort.viewportTransform" ] = = "_GridTransform" & &
stardustCompute . Ref . Metadata [ "unity.particles.vectorPort.timeVector" ] = = "_Time" & &
stardustCompute . Ref . Metadata [ "unity.particles.intPort.span" ] = = "span" & &
stardustMaterial . Ref . Metadata [ "unity.particles.bufferPort.particles" ] = = "particles" & &
stardustMaterial . Ref . Metadata [ "unity.particles.bufferPort.quadPoints" ] = = "quadPoints" & &
2026-07-16 18:16:39 +01:00
stardustMaterial . Ref . Metadata [ "unity.particles.texturePort.dither" ] = = "_DitheringTex" & &
stardustMaterial . Ref . Metadata [ "unity.particles.vectorPort.ditherCoordinates" ] = = "_DitheringCoords" & &
stardustMaterial . Ref . Metadata [ "unity.particles.intPort.frameIndex" ] = = "_FrameNumber" & &
2026-07-16 12:27:19 +01:00
stardustColors . Ref . Metadata [ "unityAssetPath" ] = = "Assets/Resources/Gradients/blackbody.png" ,
"provider asset metadata must own the exact Stardust compute/render ABI and authored color ramp" ) ;
2026-07-15 23:57:48 +01:00
var fogVolume = Flatten ( surface . Surface . Root )
. Single ( component = > string . Equals ( component . Kind , "field.volume3d" , StringComparison . Ordinal ) ) ;
Require ( fogVolume . Props . TryGetValue ( "floatParameters" , out var fogParameters ) & &
fogParameters . Contains ( "compositeOpacity=1" , StringComparison . Ordinal ) ,
"the portable fog surface must retain the fossil cloud shader's full-strength composite default" ) ;
2026-07-15 20:17:05 +01:00
}
2026-07-15 03:52:56 +01:00
private static AetheriaYmirWorldPhysics NewPhysics ( )
{
AetheriaYmirWorldPhysics physics = new ( ) ;
OwnedPhysics . Add ( physics ) ;
return physics ;
}
private static void RunCheck ( Action check )
{
try
{
check ( ) ;
}
finally
{
foreach ( var physics in OwnedPhysics )
physics . Dispose ( ) ;
OwnedPhysics . Clear ( ) ;
}
2026-07-11 18:53:20 +01:00
}
2026-07-14 16:14:59 +01:00
private static void PositiveGravityDepthAttractsAndProjectsAsAWell ( )
{
var body = new AetheriaRuntimeBodySnapshotCommit
{
BodyKey = "gravity-owner" ,
2026-07-15 23:57:48 +01:00
Kind = "gas_giant" ,
2026-07-14 16:14:59 +01:00
GravityInfluenceCenterX = 0 ,
GravityInfluenceCenterZ = 0 ,
GravityInfluenceRadius = 100 ,
2026-07-15 23:57:48 +01:00
GravityWellDepth = 20 ,
GravityWaveRadius = 80 ,
GravityWaveDepth = 3 ,
GravityWaveSpeed = 2 ,
GravityWaveFrequency = 6
2026-07-14 16:14:59 +01:00
} ;
var actor = Entity ( 0 , 10 , "player" ) ;
actor . PositionZ = 0 ;
actor . VelocityX = 0 ;
actor . VelocityY = 0 ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Bodies = [ body ] ,
Entities = [ actor ] ,
GravityTerrainRadius = 100 ,
GravityTerrainDepth = 5
} ;
2026-07-15 03:52:56 +01:00
using var physics = NewPhysics ( ) ;
2026-07-14 21:38:46 +01:00
physics . RetainWorlds ( "gravity-sign-smoke" , [ zone . ZoneIndex ] ) ;
var step = physics . Step ( "gravity-sign-smoke" , 1 , 0 , zone , zone . Entities , 0.1 ) ;
2026-07-14 16:14:59 +01:00
var steppedActor = step . Bodies . Single ( value = > value . EntityIndex = = actor . EntityIndex ) ;
Require ( steppedActor . VelocityX < 0 ,
"positive authored gravity depth must accelerate a body toward the well center through Ymir" ) ;
Require ( AetheriaRuntimeDaemonRenderQueries . EvaluateGravityTerrainHeight ( zone , 10 , 0 , 0 ) < 0 ,
"the same positive gravity-depth magnitude must project as a negative terrain well" ) ;
2026-07-14 16:26:14 +01:00
var splats = AetheriaRuntimeGameDocuments . RenderSplatsViewport (
new AetheriaRuntimeDaemonFrameDocument
{
Run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "gravity-sign-smoke" ,
CurrentZoneIndex = 0 ,
Zones = [ zone ]
}
} ,
new AetheriaRuntimeViewportBounds { MinX = - 20 , MinY = - 20 , MaxX = 20 , MaxY = 20 } ) ;
var bodySplatIndex = splats . Splats . SourceKey
. Select ( ( sourceKey , index ) = > ( sourceKey , index ) )
. Single ( value = > value . sourceKey = = body . BodyKey ) . index ;
2026-07-15 22:59:51 +01:00
var terrainSplatIndex = splats . Splats . SourceKey
. Select ( ( sourceKey , index ) = > ( sourceKey , index ) )
. Single ( value = > value . sourceKey = = "environment.gravity_terrain" ) . index ;
var fogSurfaceSplatIndex = splats . Splats . SourceKey
. Select ( ( sourceKey , index ) = > ( sourceKey , index ) )
. Single ( value = > value . sourceKey = = "environment.gravity_terrain:fog.surface_height" ) . index ;
2026-07-15 23:57:48 +01:00
var gravityWaveIndex = splats . Splats . SourceKey
. Select ( ( sourceKey , index ) = > ( sourceKey , index ) )
. Single ( value = > value . sourceKey = = body . BodyKey + ":gravity.wave" ) . index ;
var fogSurfaceWaveIndex = splats . Splats . SourceKey
. Select ( ( sourceKey , index ) = > ( sourceKey , index ) )
. Single ( value = > value . sourceKey = = body . BodyKey + ":fog.surface_height.wave" ) . index ;
var fogPatchWaveIndex = splats . Splats . SourceKey
. Select ( ( sourceKey , index ) = > ( sourceKey , index ) )
. Single ( value = > value . sourceKey = = body . BodyKey + ":fog.patch_height.wave" ) . index ;
2026-07-14 16:26:14 +01:00
Require ( splats . Splats . ValueR [ bodySplatIndex ] < 0 ,
"render-splat projection must convert positive canonical body depth into a negative gravity-height value" ) ;
2026-07-15 22:59:51 +01:00
Require ( splats . Splats . Falloff [ terrainSplatIndex ] = = EveFieldsSplatFalloffs . PowerPulse & &
splats . Splats . CenterX [ terrainSplatIndex ] = = 0 & &
splats . Splats . CenterY [ terrainSplatIndex ] = = 0 & &
splats . Splats . HalfExtentX [ terrainSplatIndex ] = = zone . GravityTerrainRadius & &
splats . Splats . FalloffScale [ terrainSplatIndex ] = = 1 ,
"zone gravity terrain must remain the fossil radial PowerPulse rather than a viewport-sized solid slab" ) ;
Require ( splats . Splats . Falloff [ bodySplatIndex ] = = EveFieldsSplatFalloffs . PowerPulse & &
splats . Splats . FalloffScale [ bodySplatIndex ] = = 2 & &
splats . Splats . FalloffExponent [ bodySplatIndex ] = = body . GravityDepthExponent ,
"body gravity wells must publish the fossil radial PowerPulse scale and exponent" ) ;
Require ( splats . Splats . LayerIndex [ fogSurfaceSplatIndex ] ! = splats . Splats . LayerIndex [ terrainSplatIndex ] & &
splats . Splats . ValueR [ fogSurfaceSplatIndex ] = = - splats . Splats . ValueR [ terrainSplatIndex ] & &
splats . Splats . ValueR [ fogSurfaceSplatIndex ] > 0 & &
splats . Splats . Falloff [ fogSurfaceSplatIndex ] = = EveFieldsSplatFalloffs . PowerPulse ,
"the fog surface must project positive fossil PowerBrush depth without changing negative gameplay terrain height" ) ;
2026-07-15 23:57:48 +01:00
foreach ( var waveIndex in new [ ] { gravityWaveIndex , fogSurfaceWaveIndex , fogPatchWaveIndex } )
{
Require ( splats . Splats . SourceKind [ waveIndex ] = = EveFieldsSplatSourceKinds . AnimatedRadialCosine & &
splats . Splats . HalfExtentX [ waveIndex ] = = body . GravityWaveRadius * 0.5 & &
splats . Splats . FrequencyX [ waveIndex ] = = body . GravityWaveFrequency & &
splats . Splats . FrequencyY [ waveIndex ] = = 1.25 & &
splats . Splats . AnimationSpeed [ waveIndex ] = = body . GravityWaveSpeed & &
splats . Splats . Falloff [ waveIndex ] = = EveFieldsSplatFalloffs . PowerPulse & &
splats . Splats . FalloffExponent [ waveIndex ] = = 8 ,
"gravity, fog surface, and fog patch height must share the exact fossil radial-wave source" ) ;
}
var patchLayerIndex = splats . Layers
. Select ( ( layer , index ) = > ( layer , index ) )
. Single ( value = > value . layer . LayerKey = = EveFieldsSplatLayerKeys . FogPatch ) . index ;
var patchLayer = splats . Layers [ patchLayerIndex ] ;
var patchMicroIndex = splats . Splats . SourceKey
. Select ( ( sourceKey , index ) = > ( sourceKey , index ) )
. Single ( value = > value . sourceKey = = "environment.fog_patch.depth_micro" ) . index ;
var patchMacroIndex = splats . Splats . SourceKey
. Select ( ( sourceKey , index ) = > ( sourceKey , index ) )
. Single ( value = > value . sourceKey = = "environment.fog_patch.depth_macro" ) . index ;
var ambientTintIndex = splats . Splats . SourceKey
. Select ( ( sourceKey , index ) = > ( sourceKey , index ) )
. Single ( value = > value . sourceKey = = "environment.fog_tint.ambient" ) . index ;
Require ( patchLayer . BlendMode = = EveFieldsSplatBlendModes . Add ,
"fossil patch depth brushes must add instead of taking the maximum" ) ;
Require ( splats . Splats . SourceKind [ patchMicroIndex ] = = EveFieldsSplatSourceKinds . AnimatedSimplexNoise & &
splats . Splats . SourceFlags [ patchMicroIndex ] = = EveFieldsSplatSourceFlags . AbsoluteValue & &
splats . Splats . FrequencyX [ patchMicroIndex ] = = 0.005 & &
splats . Splats . AnimationSpeed [ patchMicroIndex ] = = 0.025 & &
splats . Splats . HalfExtentX [ patchMicroIndex ] = = 1500 ,
"fog micro-patch must retain the fossil world-space animated absolute-simplex brush" ) ;
Require ( splats . Splats . SourceKind [ patchMacroIndex ] = = EveFieldsSplatSourceKinds . AnimatedCellNoiseB & &
splats . Splats . FrequencyX [ patchMacroIndex ] = = 0.001 & &
splats . Splats . AnimationSpeed [ patchMacroIndex ] = = 0.025 & &
splats . Splats . ValueR [ patchMacroIndex ] = = 20 ,
"fog macro-patch must retain the fossil moving cellular-B brush" ) ;
Require ( splats . Splats . ValueR [ ambientTintIndex ] > 0 & &
splats . Splats . ValueB [ ambientTintIndex ] > splats . Splats . ValueG [ ambientTintIndex ] & &
splats . Splats . ValueG [ ambientTintIndex ] > splats . Splats . ValueR [ ambientTintIndex ] ,
"fog tint must include the fossil ambient blue brush before local body lights" ) ;
Require ( ! splats . Splats . SourceKey . Contains ( "environment.fog_patch" ) & &
! splats . Splats . SourceKey . Contains ( "environment.fog_patch_height" ) ,
"the viewport-local placeholder fog producers must remain deleted" ) ;
var ordinaryPlanetSplats = AetheriaRuntimeGameDocuments . RenderSplatsViewport (
new AetheriaRuntimeDaemonFrameDocument
{
Run = new AetheriaRuntimeRunCheckpointCommit
{
CurrentZoneIndex = 0 ,
Zones =
[
new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Bodies =
[
new AetheriaRuntimeBodySnapshotCommit
{
BodyKey = "ordinary-planet" ,
Kind = "planet" ,
GravityInfluenceRadius = 20 ,
GravityWaveRadius = 20 ,
GravityWaveDepth = 4
}
]
}
]
}
} ,
new AetheriaRuntimeViewportBounds { MinX = - 30 , MinY = - 30 , MaxX = 30 , MaxY = 30 } ) ;
Require ( ! ordinaryPlanetSplats . Splats . SourceKey . Any ( key = >
key . StartsWith ( "ordinary-planet:" , StringComparison . Ordinal ) & &
key . EndsWith ( ".wave" , StringComparison . Ordinal ) ) ,
"ordinary planets must not acquire gas-giant gravity-wave visuals merely because compatibility rows contain wave values" ) ;
2026-07-15 22:59:51 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "gravity-height-smoke" ,
CurrentZoneIndex = zone . ZoneIndex ,
Zones = [ zone ]
} ;
AetheriaRuntimeDaemonSimulation . Step (
run ,
new AetheriaRuntimeDaemonIntentState ( ) ,
0.1 ,
new AetheriaRuntimeDaemonSimulationSettings ( ) ,
physics ,
simulationTimeSeconds : 0.1 ) ;
RequireNear (
AetheriaRuntimeDaemonRenderQueries . EvaluateGravityTerrainHeight (
zone , actor . PositionX , actor . PositionZ , 0.1 ) ,
actor . PositionY ,
0.0001 ,
"daemon entities must retain the fossil terrain-height projection while Ymir owns XZ physics" ) ;
2026-07-14 16:14:59 +01:00
}
2026-07-12 00:27:40 +01:00
private static void ConstantWeaponRunsOnDaemonThroughYmirBeamContact ( )
{
var source = Entity ( 0 , 0 , "player" ) ;
source . DirectionX = 1 ;
source . DirectionY = 0 ;
source . TargetEntityIndex = 2 ;
source . WeaponGroups = [ new [ ] { 0 } ] ;
2026-07-12 06:01:14 +01:00
source . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
2026-07-17 04:09:35 +01:00
{ ItemKey = "test-beam" , Quality = 0 , Durability = 1 , Enabled = true } } ,
2026-07-12 06:01:14 +01:00
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "test-beam-capacitor" , Quality = 1 , Durability = 1 , Enabled = true } }
] ;
2026-07-12 00:27:40 +01:00
source . BehaviorStates = [ new AetheriaRuntimeBehaviorStateCommit
{
2026-07-12 06:01:14 +01:00
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind , OwnerIndex = 1 , BehaviorIndex = 0 ,
2026-07-12 00:27:40 +01:00
BehaviorKind = "Capacitor" , CapacitorCharge = 10 , CapacitorCapacity = 10 , CapacitorEfficiency = 1
} ] ;
source . CargoContents = [ Cargo ( ( "beam-ammo" , 1 , 0 , 0 ) ) ] ;
var blocker = Entity ( 1 , 40 , "neutral" ) ;
var selectedTarget = Entity ( 2 , 100 , "raider" ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ source , blocker , selectedTarget ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "constant-weapon-smoke" , CurrentZoneIndex = 0 ,
2026-07-13 01:22:48 +01:00
CurrentEntityKey = AetheriaRuntimeRunCheckpointCommit . EntityRecordKey ( "constant-weapon-smoke" , 0 , 0 ) ,
Zones = [ zone ]
2026-07-12 00:27:40 +01:00
} ;
var payload = new AetheriaRuntimeBehaviorPayload ( 0 , AetheriaRuntimeBehaviorKinds . ConstantWeapon , 0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 10 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 150 ) ) ,
new AetheriaRuntimeBehaviorField ( 9 , PerformanceStat ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 10 , PerformanceStat ( 3 ) ) ,
2026-07-17 04:09:35 +01:00
new AetheriaRuntimeBehaviorField ( 11 , PerformanceStat ( 6 ) ) ,
2026-07-12 00:27:40 +01:00
new AetheriaRuntimeBehaviorField ( 12 , new AetheriaRuntimeBehaviorValue (
"item-key" , "" , 0 , false , "" , "beam-ammo" , [ ] , [ ] ) ) ,
new AetheriaRuntimeBehaviorField ( 13 , Number ( 3 ) ) ,
new AetheriaRuntimeBehaviorField ( 14 , Number ( 0.3 ) ) ,
new AetheriaRuntimeBehaviorField ( 17 , Number ( 0.15 ) )
] ) ;
2026-07-12 06:01:14 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot (
2026-07-17 04:09:35 +01:00
[WearableWeaponCatalogItem("test-beam", payload), CatalogItem("test-beam-capacitor", CapacitorPayload(10, 1))] , [ ] , [ ] ) ;
2026-07-17 03:54:33 +01:00
var press = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . SetWeaponGroupActive ,
"pilot" ,
run . RunId ,
0 ,
run . CurrentEntityKey ) ;
press . CommandId = "constant-weapon-press" ;
press . WeaponGroup = 0 ;
press . ScalarValue = 1 ;
var pressed = AetheriaRuntimeDaemonOperations . Execute (
run , [ press ] , new AetheriaRuntimeDaemonOperationContext ( ) ) ;
2026-07-12 00:27:40 +01:00
for ( var frame = 0 ; frame < 7 ; frame + + )
2026-07-17 03:54:33 +01:00
AetheriaRuntimeDaemonSimulation . Step ( run ,
frame = = 0 ? pressed . Intents : new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonSimulationSettings ( ) ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , frame , frame * 0.1 ) ;
2026-07-12 00:27:40 +01:00
var state = source . WeaponStates . Single ( value = > value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . ConstantWeapon ) ;
Require ( run . GameEvents . Count ( value = > value . Kind = = "weapon.firing.started" ) = = 1 ,
"held constant fire must publish one start transition" ) ;
Require ( run . GameEvents . Count ( value = > value . Kind = = "weapon.reload.started" ) = = 1 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.firing.stopped" ) = = 1 ,
"empty constant weapon magazine must start reload and stop the held effect once" ) ;
Require ( state . Reloading & & ! state . Firing ,
"constant weapon reload must remain authoritative persisted state" ) ;
2026-07-12 00:51:24 +01:00
Require ( Math . Abs ( Stat ( blocker , "hull" ) - 100 ) < 0.000001 & & Stat ( selectedTarget , "hull" ) < 100 ,
"constant weapon must resolve against its firing solution rather than a presentation collider" ) ;
Require ( run . ShotReceipts . Any ( value = > value . TargetEntityIndex = = selectedTarget . EntityIndex & &
value . WeaponItemKey = = "test-beam" & & value . Hit ) ,
"daemon must publish accepted continuous shot receipts with authored beam identity" ) ;
2026-07-12 00:27:40 +01:00
Require ( CargoQuantity ( source , "beam-ammo" ) = = 0 ,
"constant weapon reload must consume its reserve cargo through the shared transaction" ) ;
Require ( source . BehaviorStates . Single ( value = > value . BehaviorKind = = "Capacitor" ) . CapacitorCharge < 10 ,
"constant weapon must pay elapsed-time energy through canonical capacitor state" ) ;
2026-07-17 04:09:35 +01:00
RequireNear ( 6 , source . StatGrids . Single ( grid = >
grid . Name = = "transient-visibility:weapon:equipment:0:0" ) . Values . Single ( ) , 0.000001 ,
"constant fire must refresh its authored weapon visibility while the beam is committed" ) ;
Require ( source . Equipment [ 0 ] . Item ! . Durability < 1 ,
"constant fire must apply elapsed-time wear only while its beam transaction commits" ) ;
2026-07-12 00:27:40 +01:00
for ( var frame = 7 ; frame < 11 ; frame + + )
2026-07-17 03:54:33 +01:00
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonSimulationSettings ( ) ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , frame , frame * 0.1 ) ;
2026-07-17 03:54:33 +01:00
var release = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . SetWeaponGroupActive ,
"pilot" ,
run . RunId ,
11 ,
run . CurrentEntityKey ) ;
release . CommandId = "constant-weapon-release" ;
release . WeaponGroup = 0 ;
release . ScalarValue = 0 ;
var released = AetheriaRuntimeDaemonOperations . Execute (
run , [ release ] , new AetheriaRuntimeDaemonOperationContext ( ) ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , released . Intents , 0.1 ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonSimulationSettings ( ) ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , 11 , 1.1 ) ;
2026-07-12 00:27:40 +01:00
Require ( ! state . Firing & & run . GameEvents . Count ( value = > value . Kind = = "weapon.firing.stopped" ) = = 2 ,
2026-07-17 03:54:33 +01:00
"one release command must stop daemon-latched constant fire and publish its transition" ) ;
2026-07-12 00:27:40 +01:00
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 11 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
2026-07-13 01:22:48 +01:00
var weaponNodes = Flatten ( surface . Surface . Root ) . Where ( node = > node . Kind = = "weapon.state" ) . ToArray ( ) ;
Require ( weaponNodes . Any ( node = >
2026-07-12 00:27:40 +01:00
node . Props [ "behaviorKind" ] = = AetheriaRuntimeBehaviorKinds . ConstantWeapon & &
node . Props [ "itemKey" ] = = "test-beam" & & node . Props [ "firing" ] = = "false" ) ,
2026-07-13 01:22:48 +01:00
$"Eve world entity must project recoverable generic ConstantWeapon state; nodes={string.Join(" ; ", weaponNodes.Select(node => string.Join(" , ", node.Props.Select(pair => $" { pair . Key } = { pair . Value } "))))}" ) ;
2026-07-12 00:27:40 +01:00
Require ( Flatten ( surface . Surface . Root ) . Any ( node = > node . Kind = = "feedback.event" & &
node . Props [ "eventKind" ] = = "weapon.firing.started" & & node . Props [ "itemKey" ] = = "test-beam" ) ,
"Eve feedback stream must project continuous weapon transition chronology" ) ;
2026-07-15 09:40:12 +01:00
var cockpit = Flatten ( surface . Surface . Root ) . Single ( node = > node . Id = = "aetheria.daemon.game.cockpit" ) ;
Require ( cockpit . Kind = = "pane" & & cockpit . Props [ "role" ] = = "pilot.cockpit" & &
cockpit . Layout [ "position" ] = = "absolute" & & cockpit . Style [ "background" ] = = "transparent" ,
"pilot surface must publish a transparent provider-authored cockpit overlay" ) ;
2026-07-15 10:16:55 +01:00
Require ( Flatten ( cockpit ) . Count ( node = > node . Kind = = "progress" ) > = 7 & &
2026-07-15 09:40:12 +01:00
Flatten ( cockpit ) . Any ( node = > node . Id = = "aetheria.daemon.game.cockpit.capacitor" ) & &
2026-07-15 10:16:55 +01:00
Flatten ( cockpit ) . Any ( node = > node . Id = = "aetheria.daemon.game.cockpit.targetLock" & &
node . Props [ "label" ] = = "TARGET LOCK" ) & &
2026-07-15 09:40:12 +01:00
Flatten ( cockpit ) . Any ( node = > node . Id = = "aetheria.daemon.game.cockpit.targetHull" ) ,
"pilot cockpit must expose native ship and target instrumentation through generic Eve progress components" ) ;
Require ( Flatten ( surface . Surface . Root ) . Where ( node = >
node . Id is "aetheria.daemon.game.frame" or "aetheria.daemon.game.player" or "aetheria.daemon.game.commands" )
. All ( node = > node . Layout . TryGetValue ( "display" , out var display ) & & display = = "none" ) ,
"operator diagnostics must remain published state without becoming pilot-camera UI" ) ;
2026-07-12 00:27:40 +01:00
}
2026-07-12 00:29:35 +01:00
private static void ChargedWeaponCannotBypassChargeLifecycle ( )
{
var source = Entity ( 0 , 0 , "player" ) ;
source . DirectionX = 1 ;
2026-07-12 00:44:00 +01:00
source . TargetEntityIndex = - 1 ;
2026-07-12 00:29:35 +01:00
source . WeaponGroups = [ new [ ] { 0 } ] ;
source . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
2026-07-17 04:09:35 +01:00
{ ItemKey = "test-charged" , Quality = 0 , Durability = 1 , Enabled = true }
2026-07-12 00:29:35 +01:00
} ] ;
var target = Entity ( 1 , 80 , "raider" ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ source , target ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "charged-weapon-admission-smoke" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ]
} ;
var payload = new AetheriaRuntimeBehaviorPayload ( 0 , AetheriaRuntimeBehaviorKinds . ChargedWeapon , 0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 20 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 150 ) ) ,
2026-07-17 04:09:35 +01:00
new AetheriaRuntimeBehaviorField ( 11 , PerformanceStat ( 5 ) ) ,
2026-07-12 00:56:42 +01:00
new AetheriaRuntimeBehaviorField ( 15 , PerformanceStat ( 1000000000 ) ) ,
2026-07-12 00:29:35 +01:00
new AetheriaRuntimeBehaviorField ( 16 , PerformanceStat ( 200 ) ) ,
new AetheriaRuntimeBehaviorField ( 17 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 19 , PerformanceStat ( 0.5 ) ) ,
new AetheriaRuntimeBehaviorField ( 21 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 24 , new AetheriaRuntimeBehaviorValue ( "bool" , "" , 0 , true , "" , "" , [ ] , [ ] ) ) ,
2026-07-17 04:09:35 +01:00
new AetheriaRuntimeBehaviorField ( 27 , Number ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 30 , Number ( 3 ) )
2026-07-12 00:29:35 +01:00
] ) ;
2026-07-17 04:09:35 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot (
[WearableWeaponCatalogItem("test-charged", payload)] , [ ] , [ ] ) ;
2026-07-12 00:29:35 +01:00
var intents = new AetheriaRuntimeDaemonIntentState ( ) ;
intents . WeaponGroups . Add ( new AetheriaRuntimeDaemonWeaponGroupIntent
{
ActorEntityKey = "zone.0.entity.0" , WeaponGroup = 0 , Fire = true , Active = true
} ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , intents , 0.1 ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonSimulationSettings ( ) ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) ,
2026-07-17 04:09:35 +01:00
catalog , 0 , 0 ) ;
2026-07-12 00:29:35 +01:00
2026-07-12 01:05:25 +01:00
Require ( zone . PhysicalPayloads . Count = = 0 & & ! run . GameEvents . Any ( value = > value . Kind = = "shot.committed" ) ,
2026-07-12 00:29:35 +01:00
"pressing an authored ChargedWeapon must not bypass charging through the instant weapon resolver" ) ;
Require ( Math . Abs ( Stat ( target , "hull" ) - 100 ) < 0.000001 ,
"charged weapon admission must not apply damage before a daemon-owned release commits the shot" ) ;
2026-07-12 00:44:00 +01:00
var state = source . WeaponStates . Single ( value = > value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . ChargedWeapon ) ;
for ( var frame = 1 ; frame < 11 ; frame + + )
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonSimulationSettings ( ) ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) ,
2026-07-17 04:09:35 +01:00
catalog , frame , frame * 0.1 ) ;
2026-07-12 00:44:00 +01:00
Require ( state . Charging & & state . Charged & & state . Charge > = 1 & & state . ChargeHoldSeconds > 0 ,
"one semantic request must precharge without a firing solution and enter persisted hold state" ) ;
2026-07-12 00:54:16 +01:00
Require ( ! run . GameEvents . Any ( value = > value . Kind = = "shot.committed" ) ,
2026-07-12 00:44:00 +01:00
"ready charged weapon must hold rather than invent a firing solution" ) ;
source . TargetEntityIndex = target . EntityIndex ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonSimulationSettings ( ) ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) ,
2026-07-17 04:09:35 +01:00
catalog , 11 , 1.1 ) ;
2026-07-12 00:44:00 +01:00
Require ( run . GameEvents . Count ( value = > value . Kind = = "weapon.charge.committed" ) = = 1 & &
2026-07-12 00:54:16 +01:00
run . GameEvents . Any ( value = > value . Kind = = "shot.committed" & &
2026-07-12 00:44:00 +01:00
value . ItemKey = = "test-charged" & & Math . Abs ( value . ScalarValue - 40 ) < 0.000001 ) ,
"stored full charge must commit automatically when a firing solution becomes available" ) ;
2026-07-17 04:09:35 +01:00
RequireNear ( 15 , source . StatGrids . Single ( grid = >
grid . Name = = "transient-visibility:weapon:equipment:0:0" ) . Values . Single ( ) , 0.000001 ,
"charged fire must publish base visibility multiplied by its committed charge modifier" ) ;
Require ( source . Equipment [ 0 ] . Item ! . Durability < 1 ,
"charged hold must not suppress wear when the stored shot finally commits" ) ;
2026-07-12 00:56:42 +01:00
var miss = run . ShotReceipts . Single ( value = > value . WeaponItemKey = = "test-charged" ) ;
var missDx = miss . EndpointX - target . PositionX ;
var missDz = miss . EndpointZ - target . PositionZ ;
Require ( ! miss . Hit & & miss . AppliedDamage = = 0 & & miss . HitRoll > miss . HitProbability ,
"extreme authored dispersion must deterministically resolve a miss without damage" ) ;
2026-07-12 01:19:46 +01:00
RequireEqual ( "none" , miss . ImpactKind , "a miss must not advertise a fabricated impact response" ) ;
RequireEqual ( "bolt" , miss . PresentationKind , "instant weapon receipts must advertise a runtime-neutral travelling effect" ) ;
2026-07-12 00:56:42 +01:00
Require ( Math . Sqrt ( missDx * missDx + missDz * missDz ) > 20 & &
miss . ImpactAngleRoll > = 0 & & miss . ImpactAngleRoll < 1 & &
miss . ImpactRadiusRoll > = 0 & & miss . ImpactRadiusRoll < 1 ,
"miss receipt must carry independent named impact rolls and an endpoint outside the target silhouette" ) ;
2026-07-12 00:44:00 +01:00
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 11 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
Require ( Flatten ( surface . Surface . Root ) . Any ( node = > node . Kind = = "weapon.state" & &
node . Props . ContainsKey ( "chargeMalfunctionRisk" ) ) ,
"Eve must expose charged hold duration and malfunction risk generically" ) ;
Require ( Flatten ( surface . Surface . Root ) . Any ( node = > node . Kind = = "feedback.event" & &
node . Props [ "eventKind" ] = = "weapon.charge.committed" ) ,
"Eve feedback must expose charged solution commit chronology" ) ;
}
2026-07-13 01:22:48 +01:00
private static void InstantWeaponRequestSurvivesLockAcquisition ( )
{
var source = Entity ( 0 , 0 , "player" ) ;
source . DirectionX = 1 ;
source . VelocityX = 1 ;
source . TargetEntityIndex = 1 ;
source . Contacts = [ new AetheriaRuntimeEntityContactCommit
{
TargetEntityIndex = 1 , InfoGathered = 1 , Hostile = true , Visible = true
} ] ;
source . WeaponGroups = [ new [ ] { 0 } ] ;
source . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
2026-07-17 04:09:35 +01:00
{ ItemKey = "test-instant" , Quality = 0 , Durability = 1 , Enabled = true }
2026-07-13 01:22:48 +01:00
} ] ;
var target = Entity ( 1 , 80 , "raider" ) ;
2026-07-16 18:50:41 +01:00
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ source , target ] ,
Bodies =
[
new AetheriaRuntimeBodySnapshotCommit
{
Kind = "sun" ,
Mass = 16 ,
SunVisual = new AetheriaRuntimeSunVisualCommit
{
LightColorX = 0.5 ,
LightColorY = 0.75 ,
LightColorZ = 1 ,
LightRadiusMultiplier = 1
}
}
]
} ;
2026-07-13 01:22:48 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "instant-trigger-smoke" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ]
} ;
var payload = new AetheriaRuntimeBehaviorPayload ( 0 , AetheriaRuntimeBehaviorKinds . InstantWeapon , 0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 20 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 150 ) ) ,
2026-07-17 02:28:38 +01:00
new AetheriaRuntimeBehaviorField ( 11 , PerformanceStat ( 8 ) ) ,
2026-07-13 01:22:48 +01:00
new AetheriaRuntimeBehaviorField ( 15 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 16 , PerformanceStat ( 200 ) ) ,
new AetheriaRuntimeBehaviorField ( 17 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 19 , PerformanceStat ( 0.5 ) ) ,
2026-07-16 13:24:06 +01:00
new AetheriaRuntimeBehaviorField ( 23 , PerformanceStat ( 45 ) ) ,
new AetheriaRuntimeBehaviorField ( 24 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 25 , PerformanceStat ( 1 ) )
2026-07-13 01:22:48 +01:00
] ) ;
2026-07-17 04:09:35 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ WearableWeaponCatalogItem ( "test-instant" , payload ) ] , [ ] , [ ] ) ;
2026-07-16 13:24:06 +01:00
RequireNear ( 45 ,
AetheriaRuntimeEquippedBehaviorQueries . Find ( source , catalog , AetheriaRuntimeBehaviorKinds . InstantWeapon )
. Single ( ) . EvaluateStat ( 23 ) ,
0.000001 ,
"lock-transition fixture must retain its authored 45-degree acquisition cone" ) ;
2026-07-13 01:22:48 +01:00
var fire = new AetheriaRuntimeDaemonIntentState ( ) ;
fire . WeaponGroups . Add ( new AetheriaRuntimeDaemonWeaponGroupIntent
{
ActorEntityKey = "zone.0.entity.0" , WeaponGroup = 0 , Fire = true , Active = true
} ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , fire , 0.1 ,
2026-07-14 22:25:05 +01:00
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , 0 , 0 ) ;
2026-07-13 01:22:48 +01:00
for ( var frame = 1 ; frame < 12 & & run . ShotReceipts . Count = = 0 ; frame + + )
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
2026-07-14 22:25:05 +01:00
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , frame , frame * 0.1 ) ;
2026-07-13 01:22:48 +01:00
Require ( run . ShotReceipts . Count = = 1 & & run . ShotReceipts [ 0 ] . SourceEntityIndex = = source . EntityIndex ,
$"one instant weapon request must remain pending until daemon lock acquisition commits its shot; " +
$"receipts={run.ShotReceipts.Count}, direction={source.DirectionX},{source.DirectionY}, contacts={string.Join(" ; ", (source.Contacts ?? []).Select(value => $" { value . TargetEntityIndex } : { value . InfoGathered } "))}, states={string.Join(" ; ", (source.WeaponStates ?? []).Select(value => $" { value . BehaviorKind } : pending = { value . TriggerPending } : lock = { value . LockProgress } : target = { value . LockTargetEntityIndex } : burst = { value . BurstRemaining } "))}" ) ;
2026-07-16 13:24:06 +01:00
Require ( run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.started" & &
value . SourceEntityIndex = = 0 & & value . TargetEntityIndex = = 1 ) = = 1 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.acquired" & &
value . SourceEntityIndex = = 0 & & value . TargetEntityIndex = = 1 ) = = 1 ,
"daemon lock acquisition must publish one start and one completed transition instead of client-timed feedback" ) ;
2026-07-13 01:22:48 +01:00
var state = source . WeaponStates . Single ( value = > value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . InstantWeapon ) ;
Require ( ! state . TriggerPending ,
"instant weapon request must clear after the committed burst begins" ) ;
2026-07-17 02:28:38 +01:00
var weaponVisibility = source . StatGrids . Single ( grid = >
grid . Name = = "transient-visibility:weapon:equipment:0:0" ) ;
RequireNear ( 8 , weaponVisibility . Values . Single ( ) , 0.000001 ,
"committed instant shot must publish its authored visibility as a named transient source" ) ;
2026-07-17 04:09:35 +01:00
Require ( source . Equipment [ 0 ] . Item ! . Durability < 1 ,
"committed instant shot must apply one round of thermal wear to its owning equipment" ) ;
2026-07-17 02:28:38 +01:00
AetheriaRuntimeVisibilitySimulation . BeginTick ( [ source ] , 1 , 0.5 ) ;
RequireNear ( 8 * Math . Exp ( - 0.5 ) , weaponVisibility . Values . Single ( ) , 0.000001 ,
"weapon visibility must use the fossil exponential source decay rather than vanish with the effect" ) ;
2026-07-15 03:52:56 +01:00
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 12 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
var combat = Flatten ( surface . Surface . Root ) . Single ( node = > node . Kind = = "combat.presentation" ) ;
2026-07-15 05:57:17 +01:00
var world = Flatten ( surface . Surface . Root ) . Single ( node = > node . Kind = = "world.scene3d" ) ;
var aim = Flatten ( surface . Surface . Root ) . Single ( node = > node . Kind = = "aim.presentation" ) ;
Require ( ! string . IsNullOrWhiteSpace ( world . Props [ "lookCommand" ] ) & &
2026-07-15 06:10:08 +01:00
world . Props [ "lookModel" ] = = "planar-yaw.v1" & &
2026-07-15 05:57:17 +01:00
world . Props [ "lookSensitivityRadians" ] = = "-0.001" ,
"playable world must advertise the daemon-owned continuous look command and fossil pointer response" ) ;
2026-07-15 21:40:28 +01:00
Require ( world . Props [ "cameraRig" ] = = "perspective.entity-forward-follow.v1" & &
2026-07-15 22:32:40 +01:00
world . Props [ "cameraLookAt" ] = = "aim.convergence-point.v1" & &
2026-07-15 21:40:28 +01:00
world . Props [ "cameraDistance" ] = = "30" & &
2026-07-15 09:19:55 +01:00
world . Props [ "cameraVerticalFieldOfViewDegrees" ] = = "60" & &
2026-07-15 21:40:28 +01:00
world . Props [ "cameraTargetScreenX" ] = = "0.64" & &
2026-07-16 02:23:36 +01:00
world . Props [ "cameraTargetScreenY" ] = = "0.19" & &
2026-07-15 21:40:28 +01:00
world . Props [ "cameraPositionDamping" ] = = "0" & &
world . Props [ "cameraNearClipPlane" ] = = "1" & &
world . Props [ "cameraFarClipPlane" ] = = "4096" ,
2026-07-16 02:23:36 +01:00
"undocked world must translate the authored ARPG Third Person Rig into bottom-origin Eve viewport coordinates" ) ;
2026-07-16 18:50:41 +01:00
Require ( ! world . Props . ContainsKey ( "skyboxAssetRef" ) & &
world . Props [ "ambientLightColor" ] = = "0.5,0.75,1" & &
2026-07-15 06:39:54 +01:00
world . Props [ "reflectionAssetRef" ] = = "texture.environment.reflection" & &
2026-07-16 01:56:29 +01:00
world . Props [ "postProcessProfileAssetRef" ] = = "profile.environment.flight" & &
2026-07-16 20:57:02 +01:00
world . Props [ "colorGradingSpace" ] = = "hdr-before-tonemap.v1" & &
2026-07-16 19:56:52 +01:00
world . Props [ "exposureMode" ] = = "histogram.v1" & &
world . Props [ "exposureLowPercent" ] = = "47.37294" & &
world . Props [ "exposureHighPercent" ] = = "99" & &
world . Props [ "exposureMinimumEv" ] = = "-3" & &
world . Props [ "exposureMaximumEv" ] = = "0.3" & &
world . Props [ "exposureKeyValue" ] = = "0.5" & &
world . Props [ "exposureAdaptation" ] = = "progressive" & &
world . Props [ "exposureSpeedUp" ] = = "2" & &
world . Props [ "exposureSpeedDown" ] = = "1" & &
2026-07-16 17:54:00 +01:00
world . Props [ "cameraReconstruction" ] = = "temporal-reprojection.v1" & &
world . Props [ "temporalQuality" ] = = "high" & &
world . Props [ "temporalHistoryBlend" ] = = "0.99" & &
world . Props [ "temporalJitterScale" ] = = "0.1" & &
world . Props [ "temporalSharpening" ] = = "0" & &
2026-07-15 06:39:54 +01:00
world . Props [ "reflectionIntensity" ] = = "1" & &
2026-07-15 09:08:01 +01:00
world . Props [ "ambientLightIntensity" ] = = "1.46" & &
2026-07-16 11:35:14 +01:00
! world . Props . ContainsKey ( "keyLightDirection" ) & &
! world . Props . ContainsKey ( "keyLightColor" ) & &
! world . Props . ContainsKey ( "keyLightIntensity" ) ,
2026-07-16 18:50:41 +01:00
"playable world must light from stellar tint, use the studio HDRI only for reflections, and leave the raymarch pass in charge of the frame" ) ;
2026-07-15 05:57:17 +01:00
Require ( aim . Props [ "controlledEntityIndex" ] = = "0" & &
aim . Props [ "convergenceTargetEntityId" ] = = run . EntityRecordKey ( 0 , 1 ) & &
aim . Props [ "minimumConvergenceDistance" ] = = "50" ,
"Eve aim presentation must bind the controlled body direction to the fossil convergence semantic" ) ;
2026-07-15 03:52:56 +01:00
Require ( combat . Props [ "controlledEntityIndex" ] = = "0" & &
combat . Props [ "selectedTargetEntityIndex" ] = = "1" & &
combat . Props [ "targetVisible" ] = = "true" & &
combat . Props [ "targetHostile" ] = = "true" & &
double . Parse ( combat . Props [ "lockProgress" ] , CultureInfo . InvariantCulture ) > 0.99 ,
"Eve combat presentation must expose daemon-owned selection, contact, and completed lock without duplicating body transforms" ) ;
2026-07-15 10:16:55 +01:00
var cockpitLock = Flatten ( surface . Surface . Root ) . Single ( node = >
node . Id = = "aetheria.daemon.game.cockpit.targetLock" ) ;
Require ( cockpitLock . Kind = = "progress" & & cockpitLock . Props [ "label" ] = = "TARGET LOCK" & &
double . Parse ( cockpitLock . Props [ "value" ] , CultureInfo . InvariantCulture ) > 0.99 ,
"provider cockpit must project the same completed daemon lock through a generic Eve progress component" ) ;
2026-07-15 03:52:56 +01:00
Require ( combat . Props [ "hitMarkerDurationSeconds" ] = = "0.25" & &
combat . Props [ "radialFillMinimum" ] = = "0.25" & &
combat . Props [ "radialFillMaximum" ] = = "0.75" ,
"Eve combat presentation must preserve the fossil's presentation timing and radial meter semantics" ) ;
2026-07-16 13:24:06 +01:00
var secondTarget = Entity ( 2 , 100 , "raider" ) ;
zone . Entities = [ source , target , secondTarget ] ;
source . TargetEntityIndex = secondTarget . EntityIndex ;
source . Contacts =
[
new AetheriaRuntimeEntityContactCommit
{ TargetEntityIndex = 1 , InfoGathered = 1 , Hostile = true , Visible = true } ,
new AetheriaRuntimeEntityContactCommit
{ TargetEntityIndex = 2 , InfoGathered = 1 , Hostile = true , Visible = true }
] ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
NewPhysics ( ) , catalog , 13 , 1.3 ) ;
Require ( state . LockTargetEntityIndex = = 2 & & state . LockProgress > 0 & & state . LockProgress < 0.99 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.lost" & &
value . TargetEntityIndex = = 1 & & value . Reason = = "target-changed" ) = = 1 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.started" & &
value . TargetEntityIndex = = 2 ) = = 1 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.acquired" & &
value . TargetEntityIndex = = 2 ) = = 0 ,
$"idle authored lock behavior must tick every daemon step and transfer chronology exactly once on target change; " +
$"target={state.LockTargetEntityIndex} progress={state.LockProgress:0.###} events={string.Join('|', run.GameEvents.Where(value => value.Kind.StartsWith(" weapon . lock . ", StringComparison.Ordinal)).Select(value => $" { value . Kind } : { value . TargetEntityIndex } : { value . Reason } : { value . AuxiliaryValue : 0. # # # } - > { value . ScalarValue : 0. # # # } "))}" ) ;
for ( var frame = 14 ; frame < = 17 ; frame + + )
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
NewPhysics ( ) , catalog , frame , frame * 0.1 ) ;
Require ( state . LockProgress > 0.99 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.started" & &
value . TargetEntityIndex = = 2 ) = = 1 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.acquired" & &
value . TargetEntityIndex = = 2 ) = = 1 ,
"idle authored lock behavior must continue progressive acquisition without duplicating transition events" ) ;
source . DirectionX = - 1 ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
NewPhysics ( ) , catalog , 18 , 1.8 ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
NewPhysics ( ) , catalog , 19 , 1.9 ) ;
Require ( state . LockProgress < 0.99 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.lost" & &
value . TargetEntityIndex = = 2 & & value . Reason = = "angle" ) = = 1 ,
$"crossing the authored lock angle must publish one loss transition while continued decay remains silent; " +
$"direction={source.DirectionX},{source.DirectionY} source={source.PositionX:0.###},{source.PositionZ:0.###} target={secondTarget.PositionX:0.###},{secondTarget.PositionZ:0.###} progress={state.LockProgress:0.###} events={string.Join('|', run.GameEvents.Where(value => value.Kind.StartsWith(" weapon . lock . ", StringComparison.Ordinal)).Select(value => $" { value . Kind } : { value . TargetEntityIndex } : { value . Reason } : { value . AuxiliaryValue : 0. # # # } - > { value . ScalarValue : 0. # # # } "))}" ) ;
source . DirectionX = 1 ;
for ( var frame = 20 ; frame < = 21 ; frame + + )
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
NewPhysics ( ) , catalog , frame , frame * 0.1 ) ;
Require ( state . LockProgress > 0.99 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.acquired" & &
value . TargetEntityIndex = = 2 ) = = 2 ,
"restored facing must reacquire through a second completed transition without replaying lock start" ) ;
zone . Entities = [ source , target ] ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
NewPhysics ( ) , catalog , 22 , 2.2 ) ;
Require ( state . LockTargetEntityIndex = = - 1 & & state . LockProgress = = 0 & &
run . ShotReceipts . Count = = 1 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.lost" & &
value . TargetEntityIndex = = 2 & & value . Reason = = "target-invalid" ) = = 1 ,
$"an invalid target must clear an idle weapon's authoritative lock and publish one loss transition; " +
$"target={state.LockTargetEntityIndex} progress={state.LockProgress:0.###} shots={run.ShotReceipts.Count} events={string.Join('|', run.GameEvents.Where(value => value.Kind.StartsWith(" weapon . lock . ", StringComparison.Ordinal)).Select(value => $" { value . Kind } : { value . TargetEntityIndex } : { value . Reason } : { value . AuxiliaryValue : 0. # # # } - > { value . ScalarValue : 0. # # # } "))}" ) ;
var resetSurface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 22 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
Require ( Flatten ( resetSurface . Surface . Root ) . Any ( node = > node . Kind = = "feedback.event" & &
node . Props [ "eventKind" ] = = "weapon.lock.lost" & &
node . Props [ "targetEntityIndex" ] = = "2" & &
node . Props [ "reason" ] = = "target-invalid" & &
double . Parse ( node . Props [ "auxiliaryValue" ] , CultureInfo . InvariantCulture ) > 0.99 ) ,
"Eve feedback must project the daemon lock-loss transition and its prior completed progress" ) ;
2026-07-13 01:22:48 +01:00
}
2026-07-17 04:20:16 +01:00
private static void GuidedWeaponPublishesPresentationProfileWithoutPhysicalAuthority ( )
{
var source = Entity ( 0 , 0 , "player" ) ;
source . DirectionX = 1 ;
source . TargetEntityIndex = 1 ;
source . Contacts = [ new AetheriaRuntimeEntityContactCommit
{
TargetEntityIndex = 1 , InfoGathered = 1 , Hostile = true , Visible = true
} ] ;
source . WeaponGroups = [ new [ ] { 0 } ] ;
source . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "test-launcher" , Quality = 1 , Durability = 1 , Enabled = true }
} ] ;
var target = Entity ( 1 , 80 , "raider" ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ source , target ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "guided-presentation-smoke" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ]
} ;
var guidance = Curve (
new AetheriaRuntimeCurveKey ( 0 , 0.25 , 0 , 0 ) ,
new AetheriaRuntimeCurveKey ( 1 , 1 , 0 , 0 ) ) ;
var thrust = Curve (
new AetheriaRuntimeCurveKey ( 0 , 1 , 0 , 0 ) ,
new AetheriaRuntimeCurveKey ( 1 , 0.5 , 0 , 0 ) ) ;
var lift = Curve (
new AetheriaRuntimeCurveKey ( 0 , 0 , 0 , 0 ) ,
new AetheriaRuntimeCurveKey ( 1 , 0.75 , 0 , 0 ) ) ;
var payload = new AetheriaRuntimeBehaviorPayload ( 0 , AetheriaRuntimeBehaviorKinds . Launcher , 0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 10 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 150 ) ) ,
new AetheriaRuntimeBehaviorField ( 16 , PerformanceStat ( 20 ) ) ,
new AetheriaRuntimeBehaviorField ( 17 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 19 , PerformanceStat ( 0.1 ) ) ,
new AetheriaRuntimeBehaviorField ( 21 , PerformanceStat ( 100 ) ) ,
new AetheriaRuntimeBehaviorField ( 22 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 23 , PerformanceStat ( 180 ) ) ,
new AetheriaRuntimeBehaviorField ( 24 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 25 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 26 , guidance ) ,
new AetheriaRuntimeBehaviorField ( 27 , thrust ) ,
new AetheriaRuntimeBehaviorField ( 28 , lift ) ,
new AetheriaRuntimeBehaviorField ( 29 , PerformanceStat ( 5 ) ) ,
new AetheriaRuntimeBehaviorField ( 30 , Number ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 31 , PerformanceStat ( 40 ) )
] ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ CatalogItem ( "test-launcher" , payload ) ] , [ ] , [ ] ) ;
var fire = new AetheriaRuntimeDaemonIntentState ( ) ;
fire . WeaponGroups . Add ( new AetheriaRuntimeDaemonWeaponGroupIntent
{ ActorEntityKey = run . CurrentEntityKey , WeaponGroup = 0 , Fire = true , Active = true } ) ;
for ( var frame = 0 ; frame < 4 & & run . ShotReceipts . Count = = 0 ; frame + + )
AetheriaRuntimeDaemonSimulation . Step ( run ,
frame = = 0 ? fire : new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
NewPhysics ( ) , catalog , frame , frame * 0.1 ) ;
RequireEqual ( 0 , zone . PhysicalPayloads . Count ,
"fossil guided presentation must not be promoted into a damage-owning Ymir body" ) ;
var receipt = run . ShotReceipts . Single ( value = > value . WeaponItemKey = = "test-launcher" ) ;
RequireEqual ( "guided" , receipt . PresentationKind ,
"Launcher receipts must select the generic guided presentation path" ) ;
RequireEqual ( "target-entity" , receipt . GuidanceMode ,
"Launcher guidance must retain its fossil target-entity mode" ) ;
RequireEqual ( 2 , receipt . GuidanceCurve . Count ,
"guided receipt must retain the complete authored guidance curve" ) ;
RequireNear ( 5 , receipt . GuidanceThrust , 0.000001 ,
"guided receipt must retain evaluated authored thrust" ) ;
RequireNear ( 40 , receipt . GuidanceTopSpeed , 0.000001 ,
"guided receipt must retain evaluated authored missile velocity" ) ;
RequireNear ( 2 , receipt . GuidanceDodgeFrequency , 0.000001 ,
"guided receipt must retain authored dodge frequency" ) ;
var restored = MessagePack . MessagePackSerializer . Deserialize < AetheriaRuntimeRunCheckpointCommit > (
MessagePack . MessagePackSerializer . Serialize ( run ) ) ;
RequireEqual ( "target-entity" , restored . ShotReceipts . Single ( ) . GuidanceMode ,
"guided presentation levers must survive daemon checkpoint restart" ) ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 4 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
var shot = Flatten ( surface . Surface . Root ) . Single ( node = >
node . Kind = = "shot.receipt" & & node . Props . TryGetValue ( "itemKey" , out var itemKey ) & &
itemKey = = "test-launcher" ) ;
Require ( shot . Props [ "guidanceMode" ] = = "target-entity" & &
shot . Props [ "guidanceCurve" ] = = "0,0.25,0,0;1,1,0,0" & &
shot . Props [ "guidanceThrustCurve" ] = = "0,1,0,0;1,0.5,0,0" & &
shot . Props [ "guidanceLiftCurve" ] = = "0,0,0,0;1,0.75,0,0" ,
"generic Eve shot facts must expose the authored guidance curves without provider internals" ) ;
}
2026-07-12 01:50:18 +01:00
private static void DeployableWeaponRunsThroughYmirAndDetonatesOnDaemon ( )
{
var source = Entity ( 0 , 0 , "player" ) ;
source . DirectionX = 1 ;
source . WeaponGroups = [ new [ ] { 0 } ] ;
source . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
2026-07-17 04:09:35 +01:00
{ ItemKey = "test-mine-layer" , Quality = 0 , Durability = 1 , Enabled = true }
2026-07-12 01:50:18 +01:00
} ] ;
var target = Entity ( 1 , 50 , "neutral" ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ source , target ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "deployable-smoke" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ]
} ;
var payload = new AetheriaRuntimeBehaviorPayload ( 0 , AetheriaRuntimeBehaviorKinds . DeployableWeapon , 0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 35 ) ) ,
2026-07-12 02:25:40 +01:00
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 100 ) ) ,
2026-07-17 04:09:35 +01:00
new AetheriaRuntimeBehaviorField ( 11 , PerformanceStat ( 4 ) ) ,
2026-07-12 02:25:40 +01:00
new AetheriaRuntimeBehaviorField ( 16 , PerformanceStat ( 10 ) ) ,
2026-07-12 01:50:18 +01:00
new AetheriaRuntimeBehaviorField ( 17 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 19 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 26 , Number ( 0.2 ) ) ,
new AetheriaRuntimeBehaviorField ( 27 , Number ( 5 ) ) ,
new AetheriaRuntimeBehaviorField ( 28 , PerformanceStat ( 30 ) ) ,
new AetheriaRuntimeBehaviorField ( 29 , Number ( 0.2 ) ) ,
new AetheriaRuntimeBehaviorField ( 30 , PerformanceStat ( 50 ) )
] ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot (
2026-07-17 04:09:35 +01:00
[WearableWeaponCatalogItem("test-mine-layer", payload)] , [ ] , [ ] ) ;
2026-07-12 01:50:18 +01:00
var fire = new AetheriaRuntimeDaemonIntentState ( ) ;
fire . WeaponGroups . Add ( new AetheriaRuntimeDaemonWeaponGroupIntent
{ ActorEntityKey = "zone.0.entity.0" , WeaponGroup = 0 , Fire = true , Active = true } ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , fire , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , 1 , 0.1 ) ;
2026-07-12 01:50:18 +01:00
RequireEqual ( 1 , zone . PhysicalPayloads . Count , "deployable fire must create one persistent physical payload" ) ;
Require ( ! run . ShotReceipts . Any ( ) , "deployable fire must not masquerade as an ordinary shot receipt" ) ;
2026-07-17 04:09:35 +01:00
RequireNear ( 4 , source . StatGrids . Single ( grid = >
grid . Name = = "transient-visibility:weapon:equipment:0:0" ) . Values . Single ( ) , 0.000001 ,
"successful deployment must publish the launcher's authored weapon visibility" ) ;
Require ( source . Equipment [ 0 ] . Item ! . Durability < 1 ,
"successful deployment must apply one round of thermal wear to its launcher" ) ;
2026-07-12 01:50:18 +01:00
var mine = zone . PhysicalPayloads . Single ( ) ;
Require ( mine . PositionX > 2 & & mine . TriggeredAtSeconds < 0 ,
"Ymir must advance the unarmed mine without inventing a trigger" ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , 2 , 0.2 ) ;
2026-07-12 01:50:18 +01:00
mine = zone . PhysicalPayloads . Single ( ) ;
Require ( mine . Stationary & & mine . TriggeredAtSeconds > = 0 & &
run . GameEvents . Count ( value = > value . Kind = = "deployable.triggered" ) = = 1 ,
"an armed Ymir contact must become one daemon-owned trigger transition" ) ;
RequireNear ( 100 , Stat ( target , "hull" ) , 0.000001 ,
"trigger contact must not bypass the authored detonation delay" ) ;
2026-07-15 04:04:05 +01:00
using var soaCache = new CultCache ( ) ;
using var soaPublisher = new AetheriaRuntimeDaemonSoaFramePublisher ( soaCache , producerEpoch : 1 ) ;
var soaFrame = soaPublisher . BuildCurrentZoneEntities (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 2 , Run = run } ) ;
var mineIdentity = soaFrame . View . Identities . Single ( identity = >
identity . EntityId = = $"{run.RunId}:zone:0:physical-payload:{mine.PayloadId}" ) ;
Require ( mineIdentity . Kind = = "physical-payload" & & mineIdentity . AssetRef = = "prefab.entity.mine" & &
! mineIdentity . Selectable & & mineIdentity . EntityIndex < - 1 ,
"the playable SoA must carry the retained Ymir mine through its provider-owned asset identity" ) ;
2026-07-15 03:52:56 +01:00
var objects = AetheriaRuntimeGameDocuments . ObjectsViewport (
2026-07-12 01:50:18 +01:00
new AetheriaRuntimeDaemonFrameDocument { FrameId = 2 , Run = run } ,
2026-07-15 03:52:56 +01:00
new AetheriaRuntimeViewportBounds { MinX = - 1000 , MinY = - 1000 , MaxX = 1000 , MaxY = 1000 } ) ;
var mineObject = objects . Objects . Single ( value = > value . EntityKey = = mine . PayloadId ) ;
RequireEqual ( "projectile" , mineObject . Kind ,
"the viewport projection must expose the retained physical payload without reviving world.scene3d as a transform authority" ) ;
Require ( mineObject . IsActive & & mineObject . IconAsset ! = null ,
"the viewport projection must expose an active provider-authored presentation for the retained mine body" ) ;
Require ( mine . Stationary & & mine . TriggeredAtSeconds > = 0 ,
"daemon state must retain Ymir-derived motion and trigger state independently of presentation" ) ;
2026-07-12 01:50:18 +01:00
RequireNear ( 35 , mine . PayloadMagnitude , 0.000001 , "deployable must retain authored payload magnitude" ) ;
RequireNear ( 50 , mine . BlastRadius , 0.000001 , "deployable must retain authored blast radius" ) ;
Require ( Math . Abs ( target . PositionX - mine . PositionX ) < = mine . BlastRadius ,
$"triggered target must remain inside authored blast radius (mine {mine.PositionX}, target {target.PositionX})" ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.21 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , 3 , 0.41 ) ;
2026-07-12 01:50:18 +01:00
RequireEqual ( 0 , zone . PhysicalPayloads . Count , "detonated mine must leave canonical payload state" ) ;
RequireNear ( 65 , Stat ( target , "hull" ) , 0.000001 ,
"Aetheria must apply authored blast damage after the delay" ) ;
Require ( run . GameEvents . Count ( value = > value . Kind = = "deployable.detonated" ) = = 1 ,
"daemon must publish one authoritative detonation event" ) ;
}
2026-07-12 02:25:40 +01:00
private static void DeployableRangeExpiryDetonatesAfterYmirMovement ( )
{
var source = Entity ( 0 , - 50 , "player" ) ;
var target = Entity ( 1 , 35 , "neutral" ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ source , target ] ,
PhysicalPayloads = [ new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = "range-expiry-mine" ,
PayloadKind = "mine" ,
WeaponItemKey = "canonical-mine" ,
SourceEntityIndex = source . EntityIndex ,
PositionX = 5 ,
VelocityX = 20 ,
Radius = 1 ,
ActivationDelaySeconds = 10 ,
LifetimeSeconds = 30 ,
MaximumSourceDistance = 6 ,
BlastRadius = 50 ,
PayloadMagnitude = 15 ,
TriggeredAtSeconds = - 1 ,
Active = true
} ]
} ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "range-expiry-smoke" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ]
} ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , frameId : 4 ,
2026-07-12 02:25:40 +01:00
simulationTimeSeconds : 0.1 ) ;
RequireEqual ( 0 , zone . PhysicalPayloads . Count ,
"mine crossing source-relative range after Ymir movement must detonate in the same tick" ) ;
RequireNear ( 85 , Stat ( target , "hull" ) , 0.000001 ,
"range expiry must preserve the fossil splash consequence" ) ;
Require ( run . GameEvents . Any ( value = > value . Kind = = "deployable.expired" & &
value . Reason = = "range" & & value . ItemKey = = "canonical-mine" ) ,
"daemon must explain range-triggered expiry with stable item identity" ) ;
Require ( run . GameEvents . Any ( value = > value . Kind = = "deployable.detonated" & &
value . Reason = = "range" & & value . ItemKey = = "canonical-mine" ) ,
"range expiry must flow through the shared detonation transaction" ) ;
}
private static void CanonicalCatalogPublishesRecoveredMineLauncher ( )
{
var catalog = AetheriaRuntimeCatalogStore . OpenReadOnly (
Path . Combine ( Directory . GetCurrentDirectory ( ) , "GameData" , "aetheria-world.cc" ) ) ;
2026-07-16 15:47:38 +01:00
var drives = catalog . Items
. Where ( item = > item . BehaviorKinds . Contains ( AetheriaRuntimeBehaviorKinds . AetherDrive ) )
. ToArray ( ) ;
var driveHulls = catalog . Items
. Where ( item = > item . Hardpoints . Any ( point = > point . Type = = "AetherDrive" ) )
. ToArray ( ) ;
Require ( drives . Length = = 1 & & drives [ 0 ] . Name = = "Traction" & &
2026-07-16 17:27:01 +01:00
drives [ 0 ] . HardpointType = = "AetherDrive" & & drives [ 0 ] . Price = = 250000 & &
drives [ 0 ] . Tags . Contains ( "rarity:rare" , StringComparer . Ordinal ) ,
2026-07-16 15:47:38 +01:00
"canonical AetherDrive must remain the singular expensive Traction retrofit" ) ;
Require ( driveHulls . Length = = 1 & & driveHulls [ 0 ] . Name = = "LonginusX" & &
2026-07-16 17:27:01 +01:00
driveHulls [ 0 ] . Price = = 7500000 & &
driveHulls [ 0 ] . Tags . Contains ( "rarity:rare" , StringComparer . Ordinal ) ,
2026-07-16 15:47:38 +01:00
"canonical AetherDrive compatibility must remain confined to the rare modified LonginusX hull" ) ;
2026-07-16 17:27:01 +01:00
var ordinaryShipHulls = catalog . Items . Where ( item = > item . HullType = = "Ship" & &
item . Hardpoints . All ( point = > point . Type ! = "AetherDrive" ) & &
! item . Tags . Contains ( "rarity:rare" , StringComparer . Ordinal ) )
. ToArray ( ) ;
Require ( ordinaryShipHulls . Any ( item = > item . Name = = "Longinus" ) & &
ordinaryShipHulls . Any ( item = > item . Name = = "Djinni" ) ,
"the recovered common Longinus and Djinni must own ordinary ship generation" ) ;
2026-07-12 02:25:40 +01:00
var mine = catalog . Items . Single ( item = >
item . ItemKey = = "aetheria.item_definition:legacy:e78d3670-3ac6-4d9b-834c-1da4228ac311" ) ;
RequireEqual ( "Mine Launcher" , mine . Name , "recovered item must retain fossil identity" ) ;
RequireEqual ( "Mine" , mine . WeaponType , "recovered item must publish normalized semantic weapon type" ) ;
var behavior = mine . BehaviorPayloads . Single ( value = >
value . Kind = = AetheriaRuntimeBehaviorKinds . DeployableWeapon ) ;
RequireNear ( 2 , behavior . Fields . Single ( field = > field . Key = = 26 ) . Value . NumberValue , 0.000001 ,
"catalog mine must retain two-second activation delay" ) ;
RequireNear ( 30 , behavior . Fields . Single ( field = > field . Key = = 27 ) . Value . NumberValue , 0.000001 ,
"catalog mine must retain thirty-second lifetime" ) ;
var manifest = AetheriaRuntimeAssets . ProjectManifest ( catalog ) ;
2026-07-16 18:50:41 +01:00
Require ( ! manifest . Assets . Any ( value = > value . Ref . AssetKey = = "material.environment.skybox" ) ,
"provider catalog must not retain the obsolete skybox authority when raymarched fog owns the frame" ) ;
2026-07-15 06:39:54 +01:00
var reflection = manifest . Assets . Single ( value = > value . Ref . AssetKey = = "texture.environment.reflection" ) ;
RequireEqual ( AetheriaRuntimeAssetKinds . Texture , reflection . Ref . Kind ,
"provider must type the pre-generated environment map as a texture asset" ) ;
RequireEqual ( "environment.reflection" , reflection . Ref . Metadata [ "presentationRole" ] ,
"provider must advertise the generic reflection presentation role" ) ;
RequireEqual ( "Assets/Textures/studio2.hdr" , reflection . Ref . Metadata [ "unityAssetPath" ] ,
"provider bundle must own the pre-generated reflection map without an importer plugin" ) ;
2026-07-12 02:25:40 +01:00
var asset = manifest . Assets . Single ( value = > value . Ref . AssetKey = = "prefab.entity.mine" ) ;
RequireEqual ( "physical-payload.mine" , asset . Ref . Metadata [ "presentationRole" ] ,
"provider must advertise the script-free mine presentation role" ) ;
RequireEqual ( "0.25" , asset . Ref . Metadata [ "triggeredPulseSeconds" ] ,
"mine presentation must retain the fossil triggered pulse cadence" ) ;
2026-07-16 16:57:37 +01:00
var rareHull = driveHulls . Single ( ) ;
var rareHullAssetKey = AetheriaRuntimeAssets . HullPrefabAssetKey ( rareHull . ItemKey ) ;
var rareHullAsset = manifest . Assets . Single ( value = > value . Ref . AssetKey = = rareHullAssetKey ) ;
var expectedHullResourcePath = rareHull . HullPrefab . Replace ( '\\' , '/' ) ;
const string resourcesPrefix = "Assets/Resources/" ;
if ( expectedHullResourcePath . StartsWith ( resourcesPrefix , StringComparison . OrdinalIgnoreCase ) )
expectedHullResourcePath = expectedHullResourcePath [ resourcesPrefix . Length . . ] ;
if ( expectedHullResourcePath . EndsWith ( ".prefab" , StringComparison . OrdinalIgnoreCase ) )
expectedHullResourcePath = expectedHullResourcePath [ . . ^ ".prefab" . Length ] ;
RequireEqual ( "entity.hull" , rareHullAsset . Ref . Metadata [ "presentationRole" ] ,
"provider manifest must type catalog hull prefabs as generic hull presentation assets" ) ;
RequireEqual ( expectedHullResourcePath , rareHullAsset . Ref . Metadata [ "resourcesPath" ] ,
"provider hull asset must retain the catalog-authored prefab instead of a faction fallback" ) ;
var rareShip = Entity ( 0 , 0 , "player" ) ;
rareShip . HullItemKey = rareHull . ItemKey ;
var rareRun = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "rare-hull-presentation-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ rareShip ] } ]
} ;
var rareFrame = new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = rareRun } ;
var rareSurface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
rareFrame ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ,
catalog : catalog ) ;
var rareSurfaceEntity = Flatten ( rareSurface . Surface . Root ) . Single ( node = >
node . Id = = "aetheria.daemon.game.world.entity.0" ) ;
RequireEqual ( rareHullAssetKey , rareSurfaceEntity . Props [ "assetRef" ] ,
"Eve scene projection must select the typed hull asset rather than the player Djinni fallback" ) ;
using var rareSoaCache = new CultCache ( ) ;
using var rareSoaPublisher = new AetheriaRuntimeDaemonSoaFramePublisher ( rareSoaCache , producerEpoch : 1 ) ;
var rareSoa = rareSoaPublisher . BuildCurrentZoneEntities ( rareFrame , catalog ) ;
RequireEqual ( rareHullAssetKey , rareSoa . View . Identities . Single ( ) . AssetRef ,
"SoA identity and Eve scene projection must share the catalog-owned hull asset key" ) ;
2026-07-12 02:25:40 +01:00
}
2026-07-12 02:38:06 +01:00
private static void EnergyFundedShieldInterceptsDamageBeforeHull ( )
{
var source = Entity ( 0 , - 50 , "player" ) ;
var target = Entity ( 1 , 0 , "neutral" ) ;
2026-07-12 06:01:14 +01:00
target . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "test-energy-shield" , Quality = 1 , Durability = 1 , Enabled = true } } ,
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "test-shield-capacitor" , Quality = 1 , Durability = 1 , Enabled = true } }
] ;
2026-07-12 02:38:06 +01:00
target . BehaviorStates = [ new AetheriaRuntimeBehaviorStateCommit
{
2026-07-12 06:01:14 +01:00
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind , OwnerIndex = 1 , BehaviorIndex = 0 ,
2026-07-12 02:38:06 +01:00
BehaviorKind = "Capacitor" , CapacitorCharge = 100 , CapacitorCapacity = 100 ,
CapacitorEfficiency = 1
} ] ;
var shield = new AetheriaRuntimeBehaviorPayload ( 0 , "Shield" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 3 ) )
] ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot (
2026-07-12 06:01:14 +01:00
[CatalogItem("test-energy-shield", shield), CatalogItem("test-shield-capacitor", CapacitorPayload(100, 1))] , [ ] , [ ] ) ;
2026-07-12 02:38:06 +01:00
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ source , target ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "energy-shield-smoke" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ]
} ;
void AddDetonatingPayload ( string id , double damage )
{
zone . PhysicalPayloads = [ new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = id , PayloadKind = "mine" , WeaponItemKey = "test-blast" ,
SourceEntityIndex = source . EntityIndex , PositionX = target . PositionX ,
LifetimeSeconds = 30 , BlastRadius = 10 , PayloadMagnitude = damage ,
TriggeredAtSeconds = 0 , DetonationDelaySeconds = 0 , Stationary = true , Active = true
} ] ;
}
AddDetonatingPayload ( "shielded-blast" , 20 ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , 1 , 0.1 ) ;
2026-07-12 02:38:06 +01:00
var capacitor = target . BehaviorStates . Single ( value = > value . BehaviorKind = = "Capacitor" ) ;
RequireNear ( 100 , Stat ( target , "hull" ) , 0.000001 ,
"funded shield must intercept damage before hull" ) ;
RequireNear ( 40 , capacitor . CapacitorCharge , 0.000001 ,
"shield must consume damage multiplied by authored energy usage" ) ;
RequireNear ( 40.0 / 3.0 , Stat ( target , "shield" ) , 0.000001 ,
"legacy shield meter must be derived from remaining funded absorption, not own hit points" ) ;
Require ( run . GameEvents . Any ( value = > value . Kind = = "shield.absorbed" & &
Math . Abs ( value . ScalarValue - 20 ) < 0.000001 & &
Math . Abs ( value . AuxiliaryValue - 10 ) < 0.000001 ) ,
"shield outcome must publish absorbed damage and authored heat contribution" ) ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
Require ( Flatten ( surface . Surface . Root ) . Any ( node = > node . Kind = = "feedback.event" & &
node . Props [ "eventKind" ] = = "shield.absorbed" & &
node . Props [ "scalarValue" ] = = "20" & & node . Props [ "auxiliaryValue" ] = = "10" ) ,
"Eve feedback must expose exact shield absorption and heat facts" ) ;
var shieldAsset = AetheriaRuntimeAssets . ProjectManifest ( catalog ) . Assets . Single ( value = >
value . Ref . Metadata . TryGetValue ( "presentationRole" , out var role ) & & role = = "effect.impact.shield" ) ;
RequireEqual ( "prefab.effect.impact.shield" , shieldAsset . Ref . AssetKey ,
"provider must advertise the authored shield visual by semantic impact role" ) ;
capacitor . CapacitorCharge = 0 ;
AddDetonatingPayload ( "unfunded-blast" , 20 ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , 2 , 0.2 ) ;
2026-07-12 02:38:06 +01:00
RequireNear ( 80 , Stat ( target , "hull" ) , 0.000001 ,
"unfunded shield must not manufacture absorption" ) ;
}
2026-07-12 05:13:03 +01:00
private static void ArmorCellsResolveBeforeEquipmentAndHull ( )
{
var source = Entity ( 0 , - 100 , "player" ) ;
var target = Entity ( 1 , 0 , "neutral" ) ;
target . HullItemKey = "test-cell-hull" ;
target . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 0 , Y = 1 ,
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "test-cell-gear" , Quality = 1 , Durability = 2 , Enabled = true }
} ] ;
var hull = HullCatalogItem ( "test-cell-hull" , 3 , 3 , 5 ) ;
var gear = CatalogItem ( "test-cell-gear" ) ;
gear . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , gear ] , [ ] , [ ] ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{ ZoneIndex = 0 , Entities = [ source , target ] , PhysicalPayloads = [ new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = "armor-blast" , PayloadKind = "mine" , WeaponItemKey = "test-cannon" ,
SourceEntityIndex = source . EntityIndex , PositionX = target . PositionX , PositionZ = target . PositionZ ,
LifetimeSeconds = 30 , BlastRadius = 200 , PayloadMagnitude = 20 ,
DamageType = "Corrosive" , Penetration = 0 , DamageSpread = 0 ,
TriggeredAtSeconds = 0 , DetonationDelaySeconds = 0 , Stationary = true , Active = true
} ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{ RunId = "armor-cell-smoke" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ] } ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , 1 , 0.1 ) ;
2026-07-12 05:13:03 +01:00
var armor = target . StatGrids . Single ( value = > value . Name = = "armor" ) ;
RequireNear ( 0 , armor . Values [ 3 ] , 0.000001 , "source-facing splash cells must absorb damage first" ) ;
RequireNear ( 1.0 / 3.0 , target . Equipment . Single ( ) . Item . Durability , 0.000001 ,
"installed equipment at the impact cell must receive residual damage second" ) ;
RequireNear ( 100 - ( 10.0 / 3.0 ) , Stat ( target , "hull" ) , 0.000001 ,
"only residual damage after armor and equipment may reach hull durability" ) ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
var targetNode = Flatten ( surface . Surface . Root ) . Single ( node = >
node . Id = = "aetheria.daemon.game.world.entity.1" ) ;
2026-07-15 03:52:56 +01:00
RequireEqual ( "entity.presentation" , targetNode . Kind ,
"Eve semantic entity facts must not become a second body-transform authority" ) ;
2026-07-12 05:13:03 +01:00
RequireEqual ( "30" , targetNode . Props [ "armor" ] ,
"Eve world projection must expose aggregate armor as derived presentation state" ) ;
RequireEqual ( "0,5,5,0,5,5,0,5,5" , targetNode . Props [ "armorGrid" ] ,
"Eve world projection must expose the exact daemon-owned schematic grid" ) ;
}
2026-07-17 04:27:37 +01:00
private static void ShipSchematicProjectsDaemonTopologyAndEquipmentState ( )
{
var player = Entity ( 0 , - 50 , "player" ) ;
player . TargetEntityIndex = 1 ;
var target = Entity ( 1 , 0 , "raider" ) ;
var observed = Entity ( 2 , 50 , "neutral" ) ;
target . HullItemKey = "schematic-hull" ;
target . StatGrids =
[
Grid ( "hull" , 100 ) , Grid ( "shield" , 0 ) , Grid ( "heat" , 400 ) ,
Grid ( "armor" , 3 , 2 , 10 , 8 , 6 , 4 , 2 , 0 ) ,
Grid ( "maximumArmor" , 3 , 2 , 10 , 10 , 10 , 10 , 10 , 10 )
] ;
target . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 1 , Y = 0 , Rotation = "Clockwise" ,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = "schematic-launcher" , Quality = 1 , Durability = 5 ,
Temperature = 400 , Enabled = true
}
} ] ;
target . EquipmentStates = [ new AetheriaRuntimeEquipmentStateCommit
{
EquipmentIndex = 0 , Temperature = 400 , ThermalPerformance = 0.75 ,
DurabilityPerformance = 0.5 , Wear = 0.02 , Online = true ,
ThermalOnline = true , DurabilityOnline = true
} ] ;
target . WeaponStates = [ new AetheriaRuntimeWeaponStateCommit
{
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ,
OwnerIndex = 0 , BehaviorIndex = 0 , BehaviorKind = AetheriaRuntimeBehaviorKinds . Launcher ,
Ammo = 3 , CooldownProgress = 0.4 , CoolingDown = true
} ] ;
var hull = HullCatalogItem ( "schematic-hull" , 3 , 2 , 10 ) ;
var launcher = CatalogItem ( "schematic-launcher" , new AetheriaRuntimeBehaviorPayload (
0 , AetheriaRuntimeBehaviorKinds . Launcher , 0 , [ ] ) ) ;
launcher . ShapeWidth = 2 ;
launcher . ShapeHeight = 1 ;
launcher . OccupiedCells = 2 ;
launcher . ShapeCells =
[
new AetheriaRuntimeShapeCell ( 0 , 0 ) ,
new AetheriaRuntimeShapeCell ( 1 , 0 )
] ;
launcher . Durability = 10 ;
launcher . MinimumTemperature = 200 ;
launcher . MaximumTemperature = 600 ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , launcher ] , [ ] , [ ] ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ player , target , observed ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "schematic-surface-smoke" , CurrentZoneIndex = 0 ,
CurrentEntityKey = AetheriaRuntimeRunCheckpointCommit . EntityRecordKey (
"schematic-surface-smoke" , 0 , player . EntityIndex ) ,
Zones = [ zone ]
} ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ,
catalog : catalog ) ;
var schematic = Flatten ( surface . Surface . Root ) . Single ( node = >
node . Id = = "aetheria.daemon.game.world.entity.1.schematic" ) ;
Require ( schematic . Kind = = "ship.schematic" & & schematic . Props [ "role" ] = = "target" & &
schematic . Props [ "width" ] = = "3" & & schematic . Props [ "height" ] = = "2" ,
"selected target must publish its daemon-owned hull topology as a generic ship schematic" ) ;
var hullCells = Flatten ( schematic ) . Where ( node = > node . Kind = = "schematic.hull-cell" ) . ToArray ( ) ;
RequireEqual ( 6 , hullCells . Length ,
"schematic must publish every occupied hull cell rather than a renderer-invented rectangle" ) ;
var damagedCell = hullCells . Single ( node = > node . Props [ "x" ] = = "1" & & node . Props [ "y" ] = = "0" ) ;
Require ( damagedCell . Props [ "armor" ] = = "8" & & damagedCell . Props [ "maximumArmor" ] = = "10" & &
damagedCell . Props [ "armorRatio" ] = = "0.8" ,
"schematic cell must expose exact current and maximum daemon armor" ) ;
var item = Flatten ( schematic ) . Single ( node = > node . Kind = = "schematic.item" ) ;
Require ( item . Props [ "itemKey" ] = = "schematic-launcher" & & item . Props [ "durabilityRatio" ] = = "0.5" & &
item . Props [ "temperatureRatio" ] = = "0.5" & & item . Props [ "thermalPerformance" ] = = "0.75" & &
item . Props [ "online" ] = = "true" ,
"schematic item must expose daemon-derived durability and thermal state" ) ;
var itemCells = Flatten ( item ) . Where ( node = > node . Kind = = "schematic.item-cell" )
. Select ( node = > $"{node.Props[" x "]},{node.Props[" y "]}" ) . ToArray ( ) ;
RequireEqual ( "1,0;1,1" , string . Join ( ";" , itemCells ) ,
"schematic footprint must use the same clockwise placement geometry as refit and damage" ) ;
var weapon = Flatten ( item ) . Single ( node = > node . Kind = = "schematic.weapon" ) ;
Require ( weapon . Props [ "ammo" ] = = "3" & & weapon . Props [ "cooldownProgress" ] = = "0.4" ,
"schematic weapon row must expose authoritative ammo and cooldown levers" ) ;
Require ( Flatten ( surface . Surface . Root ) . Single ( node = >
node . Id = = "aetheria.daemon.game.world.entity.0.schematic" ) . Props [ "role" ] = = "self" ,
"controlled entity must publish the same schematic contract with a self role" ) ;
Require ( ! Flatten ( surface . Surface . Root ) . Any ( node = >
node . Id = = "aetheria.daemon.game.world.entity.2.schematic" ) ,
"unselected observed entities must not bloat the live surface with unused schematic trees" ) ;
}
2026-07-16 21:14:03 +01:00
private static void EquipmentDestructionDisablesBehaviorAndCockpitKillsBeforeHull ( )
{
var source = Entity ( 0 , - 100 , "player" ) ;
var target = Entity ( 1 , 0 , "neutral" ) ;
target . HullItemKey = "equipment-damage-hull" ;
target . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 0 , Y = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "damageable-weapon" , Quality = 1 , Durability = 1 , Enabled = true }
} ] ;
target . WeaponStates = [ new AetheriaRuntimeWeaponStateCommit
{
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ,
OwnerIndex = 0 , BehaviorIndex = 0 , BehaviorKind = "InstantWeapon" ,
Firing = true , TriggerPending = true , BurstRemaining = 2 ,
Charging = true , Charged = true , Charge = 1 ,
LockProgress = 1 , LockTargetEntityIndex = source . EntityIndex
} ] ;
var hull = HullCatalogItem ( "equipment-damage-hull" , 1 , 1 , 0 ) ;
var weapon = CatalogItem ( "damageable-weapon" , new AetheriaRuntimeBehaviorPayload (
0 , "InstantWeapon" , 0 , [ ] ) ) ;
weapon . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , weapon ] , [ ] , [ ] ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 , Entities = [ source , target ] , PhysicalPayloads = [ new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = "equipment-destruction" , PayloadKind = "mine" , WeaponItemKey = "test-cannon" ,
SourceEntityIndex = source . EntityIndex , PositionX = target . PositionX , PositionZ = target . PositionZ ,
LifetimeSeconds = 30 , BlastRadius = 200 , PayloadMagnitude = 1 ,
TriggeredAtSeconds = 0 , DetonationDelaySeconds = 0 , Stationary = true , Active = true
} ]
} ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "equipment-destruction-smoke" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ]
} ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault , NewPhysics ( ) , catalog , 1 , 0.1 ) ;
Require ( target . IsActive & & Math . Abs ( Stat ( target , "hull" ) - 100 ) < 0.000001 ,
"destroying ordinary equipment must not manufacture hull damage or destroy the entity" ) ;
RequireNear ( 0 , target . Equipment . Single ( ) . Item . Durability , 0.000001 ,
"equipment damage must durably cross into the fossil destroyed state" ) ;
RequireEqual ( 1 , AetheriaRuntimeEquippedBehaviorQueries . Find ( target , catalog , "InstantWeapon" ) . Count ,
"destroyed equipment must remain installed as durable loadout state" ) ;
RequireEqual ( 0 , AetheriaRuntimeEquippedBehaviorQueries . FindOperational ( target , catalog , "InstantWeapon" ) . Count ,
"destroyed equipment behavior must stop contributing immediately" ) ;
var destroyedWeaponState = target . WeaponStates . Single ( ) ;
Require ( ! destroyedWeaponState . Firing & & ! destroyedWeaponState . TriggerPending & &
! destroyedWeaponState . Charging & & ! destroyedWeaponState . Charged & &
destroyedWeaponState . BurstRemaining = = 0 & & destroyedWeaponState . LockTargetEntityIndex < 0 ,
"destroyed weapon state must deactivate atomically instead of publishing a ghost firing effect" ) ;
RequireEqual ( 1 , run . GameEvents . Count ( value = > value . Kind = = "equipment.destroyed" & &
value . TargetEntityIndex = = target . EntityIndex & & value . ItemKey = = "damageable-weapon" ) ,
"the durability crossing must publish exactly one generic equipment destruction fact" ) ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
Require ( Flatten ( surface . Surface . Root ) . Any ( node = > node . Kind = = "feedback.event" & &
node . Props [ "eventKind" ] = = "equipment.destroyed" & &
node . Props [ "itemKey" ] = = "damageable-weapon" ) ,
"generic Eve clients must receive equipment destruction through provider feedback facts" ) ;
var cockpitTarget = Entity ( 2 , 0 , "neutral" ) ;
cockpitTarget . HullItemKey = "cockpit-damage-hull" ;
cockpitTarget . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 0 , Y = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "damageable-cockpit" , Quality = 1 , Durability = 1 , Enabled = true }
} ] ;
var cockpitHull = HullCatalogItem ( "cockpit-damage-hull" , 1 , 1 , 0 ) ;
var cockpit = CatalogItem ( "damageable-cockpit" , new AetheriaRuntimeBehaviorPayload ( 0 , "Cockpit" , 0 , [ ] ) ) ;
cockpit . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var cockpitCatalog = new AetheriaRuntimeCatalogSnapshot ( [ cockpitHull , cockpit ] , [ ] , [ ] ) ;
var cockpitZone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 , Entities = [ source , cockpitTarget ] , PhysicalPayloads = [ new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = "cockpit-destruction" , PayloadKind = "mine" , WeaponItemKey = "test-cannon" ,
SourceEntityIndex = source . EntityIndex , PositionX = cockpitTarget . PositionX , PositionZ = cockpitTarget . PositionZ ,
LifetimeSeconds = 30 , BlastRadius = 200 , PayloadMagnitude = 1 ,
TriggeredAtSeconds = 0 , DetonationDelaySeconds = 0 , Stationary = true , Active = true
} ]
} ;
var cockpitRun = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "cockpit-destruction-smoke" , CurrentZoneIndex = 0 ,
2026-07-16 23:42:27 +01:00
CurrentEntityKey = AetheriaRuntimeRunCheckpointCommit . EntityRecordKey (
"cockpit-destruction-smoke" , 0 , cockpitTarget . EntityIndex ) ,
Zones = [ cockpitZone ]
2026-07-16 21:14:03 +01:00
} ;
AetheriaRuntimeDaemonSimulation . Step ( cockpitRun , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault , NewPhysics ( ) , cockpitCatalog , 1 , 0.1 ) ;
Require ( ! cockpitTarget . IsActive & & cockpitTarget . CauseOfDeath = = "cockpit-destroyed" ,
"cockpit durability crossing must use the fossil cockpit death path before hull depletion" ) ;
RequireNear ( 100 , Stat ( cockpitTarget , "hull" ) , 0.000001 ,
"cockpit destruction must not counterfeit scalar hull depletion" ) ;
var chronology = cockpitRun . GameEvents . Where ( value = >
value . Kind = = "equipment.destroyed" | | value . Kind = = "entity.destroyed" )
. Select ( value = > value . Kind ) . ToArray ( ) ;
RequireEqual ( "equipment.destroyed,entity.destroyed" , string . Join ( "," , chronology ) ,
"equipment destruction feedback must precede the cause-specific entity destruction fact" ) ;
2026-07-16 23:42:27 +01:00
RequireEqual ( AetheriaRuntimeRunLifecycle . Failed , cockpitRun . LifecyclePhase ,
"destruction of the controlled entity must end the daemon-owned run" ) ;
RequireEqual ( "cockpit-destroyed" , cockpitRun . TerminalReason ,
"the run terminal reason must preserve the fossil cause of death" ) ;
RequireEqual ( 1L , cockpitRun . TerminalFrameId ,
"the run terminal frame must be committed with the lethal transaction" ) ;
RequireEqual ( "" , cockpitRun . CurrentEntityKey ,
"the failed run must release its controlled entity after recording the terminal cause" ) ;
RequireEqual ( 1 , cockpitRun . GameEvents . Count ( value = > value . Kind = = "run.failed" & &
value . Reason = = "cockpit-destroyed" ) ,
"the lethal transaction must publish one durable run failure fact" ) ;
var restartedRun = MessagePack . MessagePackSerializer . Deserialize < AetheriaRuntimeRunCheckpointCommit > (
MessagePack . MessagePackSerializer . Serialize ( cockpitRun ) ) ;
restartedRun . Zones [ 0 ] . Entities [ 0 ] . VelocityX = 10 ;
var sourcePosition = restartedRun . Zones [ 0 ] . Entities [ 0 ] . PositionX ;
var rejectedAfterFailure = MovementCommand ( "move-after-run-failure" , "zone.0.entity.0" , 1 , 0 ) ;
using var restartedPhysics = NewPhysics ( ) ;
var restarted = AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-failed-run-restart.cc" ) ,
restartedRun ,
new AetheriaRuntimeDaemonTickOptions
{
FrameId = 2 ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = 0.2 ,
ObservedCommands = [ rejectedAfterFailure ] ,
WorldPhysics = restartedPhysics ,
BuildPublications = false
} ) ;
Require ( restarted . OperationResult . RejectedCommandIds . Contains ( "move-after-run-failure" ) ,
"a terminal run must reject later gameplay commands after restart" ) ;
RequireNear ( sourcePosition , restartedRun . Zones [ 0 ] . Entities [ 0 ] . PositionX , 0.000001 ,
"a terminal run must not advance surviving world bodies after restart" ) ;
RequireEqual ( 1 , restartedRun . GameEvents . Count ( value = > value . Kind = = "run.failed" ) ,
"restart must not replay the run failure transition" ) ;
var failedSurface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
restarted . Frame ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
var failedWorld = Flatten ( failedSurface . Surface . Root )
. Single ( node = > node . Id = = "aetheria.daemon.game.world" ) ;
RequireEqual ( "terminal" , failedWorld . Props [ "presentationMode" ] ,
"the generic Eve world must receive a terminal presentation lever" ) ;
RequireEqual ( "false" , failedWorld . Props [ "movementEnabled" ] ,
"the generic Eve world must not advertise movement after run failure" ) ;
RequireEqual ( "cockpit-destroyed" , failedWorld . Props [ "runTerminalReason" ] ,
"the generic Eve world must receive the authoritative terminal cause" ) ;
Require ( AetheriaRuntimeStateRefResolver . TryResolveDaemonStateRef (
restarted . Frame ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ,
AetheriaRuntimeDaemonStateRefs . CurrentRunLifecycle ,
out var projectedLifecycle ) & &
projectedLifecycle = = AetheriaRuntimeRunLifecycle . Failed ,
"Eve state bindings must resolve the daemon-owned run lifecycle without client inference" ) ;
2026-07-16 21:14:03 +01:00
}
2026-07-12 05:32:03 +01:00
private static void DestructionDropsLootExactlyOnce ( )
{
var source = Entity ( 0 , - 100 , "player" ) ;
var target = Entity ( 1 , 0 , "raider" ) ;
target . HullItemKey = "drop-hull" ;
target . StatGrids = [ Grid ( "hull" , 1 ) , Grid ( "shield" , 0 ) , Grid ( "heat" , 0 ) ] ;
target . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "drop-gear" , Quality = 0.8 , Durability = 0.6 , Quantity = 1 , Enabled = true }
} ] ;
target . CargoContents = [ Cargo ( ( "drop-cargo" , 4 , 0 , 0 ) ) ] ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 , Entities = [ source , target ] ,
PhysicalPayloads = [ new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = "destruction-mine" , PayloadKind = "mine" , WeaponItemKey = "destruction-charge" ,
SourceEntityIndex = 0 , PositionX = 0 , PositionZ = 0 , BlastRadius = 200 ,
PayloadMagnitude = 20 , TriggeredAtSeconds = 0 , DetonationDelaySeconds = 0 ,
LifetimeSeconds = 30 , Active = true , Stationary = true
} ]
} ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "destruction-smoke" , GenerationSeed = 29 , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ]
} ;
var settings = LootSettings ( 1 ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 , settings ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , null , 1 , 0.1 ) ;
2026-07-12 05:32:03 +01:00
Require ( ! target . IsActive & & target . DestroyedFrameId = = 1 & &
! string . IsNullOrWhiteSpace ( target . DestructionId ) ,
"lethal daemon damage must commit one durable destruction identity and deactivate the entity" ) ;
2026-07-15 05:30:06 +01:00
RequireEqual ( 2 , zone . DroppedPickups . Count ,
"guaranteed fossil loot roll must drop non-hull equipment and every cargo stack" ) ;
Require ( ! zone . DroppedPickups . Any ( value = > value . Item . ItemKey = = "drop-hull" ) ,
"the equipped hull must remain excluded from fossil destruction loot" ) ;
2026-07-12 05:32:03 +01:00
RequireEqual ( 4 , zone . DroppedPickups . Single ( value = > value . Item . ItemKey = = "drop-cargo" ) . Item . Quantity ,
"cargo drops must preserve exact stack quantity" ) ;
Require ( zone . DroppedPickups . All ( value = > Math . Abs ( Math . Sqrt (
value . VelocityX * value . VelocityX + value . VelocityY * value . VelocityY +
value . VelocityZ * value . VelocityZ ) - 25 ) < 0.000001 & &
Math . Abs ( value . LifetimeSeconds - 30 ) < 0.000001 ) ,
"destruction pickups must retain fossil launch speed and lifetime" ) ;
2026-07-15 05:30:06 +01:00
RequireEqual ( 2 , run . GameEvents . Count ( value = > value . Kind = = "pickup.dropped" ) ,
2026-07-12 05:32:03 +01:00
"each durable pickup must publish one drop event" ) ;
RequireEqual ( 1 , run . GameEvents . Count ( value = > value . Kind = = "entity.destroyed" ) ,
"destruction chronology must publish exactly once" ) ;
2026-07-16 23:42:27 +01:00
RequireEqual ( AetheriaRuntimeRunLifecycle . Active , run . LifecyclePhase ,
"destroying a non-controlled entity must not counterfeit a run failure" ) ;
2026-07-12 05:32:03 +01:00
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
Require ( ! Flatten ( surface . Surface . Root ) . Any ( node = > node . Id = = "aetheria.daemon.game.world.entity.1" ) ,
"Eve must not project a destroyed tombstone as an active world entity" ) ;
var destructionAsset = AetheriaRuntimeAssets . ProjectManifest ( null ) . Assets . Single ( value = >
value . Ref . Metadata . TryGetValue ( "presentationRole" , out var role ) & &
role = = "effect.feedback.entity.destroyed" ) ;
RequireEqual ( "prefab.effect.entity.destroyed" , destructionAsset . Ref . AssetKey ,
"provider must advertise the original destruction effect by semantic feedback role" ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 , settings ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , null , 2 , 0.2 ) ;
2026-07-15 05:30:06 +01:00
RequireEqual ( 2 , zone . DroppedPickups . Count ,
2026-07-12 05:32:03 +01:00
"later ticks must not duplicate an already committed destruction transaction" ) ;
RequireEqual ( 1 , run . GameEvents . Count ( value = > value . Kind = = "entity.destroyed" ) ,
"later ticks must not duplicate destruction chronology" ) ;
}
2026-07-12 00:44:00 +01:00
private static void ChargedWeaponHoldRiskMalfunctionsDeterministically ( )
{
var source = Entity ( 0 , 0 , "player" ) ;
source . WeaponGroups = [ new [ ] { 0 } ] ;
var item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "risk-charger" , Quality = 1 , Durability = 1 , Enabled = true } ;
source . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit { Item = item } ] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "charged-risk-smoke" , GenerationSeed = 17 ,
CurrentZoneIndex = 0 , CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ source ] } ]
} ;
var payload = new AetheriaRuntimeBehaviorPayload ( 0 , AetheriaRuntimeBehaviorKinds . ChargedWeapon , 0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 20 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 150 ) ) ,
new AetheriaRuntimeBehaviorField ( 17 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 19 , PerformanceStat ( 0.5 ) ) ,
new AetheriaRuntimeBehaviorField ( 21 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 25 , Number ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 26 , Number ( 0.25 ) )
] ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ CatalogItem ( item . ItemKey , payload ) ] , [ ] , [ ] ) ;
for ( var frame = 0 ; frame < 21 ; frame + + )
{
var intents = new AetheriaRuntimeDaemonIntentState ( ) ;
if ( frame = = 0 ) intents . WeaponGroups . Add ( new AetheriaRuntimeDaemonWeaponGroupIntent
{ ActorEntityKey = "zone.0.entity.0" , WeaponGroup = 0 , Fire = true , Active = true } ) ;
AetheriaRuntimeDaemonSimulation . Step ( run , intents , 0.1 ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonSimulationSettings ( ) ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , frame , frame * 0.1 ) ;
2026-07-12 00:44:00 +01:00
}
var state = source . WeaponStates . Single ( value = > value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . ChargedWeapon ) ;
Require ( ! state . Charging & & ! state . Charged & & state . CoolingDown & & state . ChargeRiskChecks = = 1 & &
Math . Abs ( state . ChargeMalfunctionRisk - 1 ) < 0.000001 ,
"held full charge must persist its risk check and fail when authored risk reaches certainty" ) ;
RequireNear ( 0.75 , item . Durability , 0.000001 ,
"charged malfunction must damage canonical equipped-item durability" ) ;
Require ( run . GameEvents . Count ( value = > value . Kind = = "weapon.charge.malfunctioned" & &
value . SubjectKey = = "hold-risk" & & value . ItemKey = = item . ItemKey ) = = 1 ,
"charged hold risk must emit one authoritative malfunction event" ) ;
2026-07-12 00:54:16 +01:00
Require ( ! run . GameEvents . Any ( value = > value . Kind = = "shot.committed" ) ,
2026-07-12 00:44:00 +01:00
"malfunction without a firing solution must never leak a projectile" ) ;
2026-07-12 00:29:35 +01:00
}
2026-07-11 18:53:20 +01:00
private static void AgentTowsStationIntoPersistentOrbit ( )
{
var tug = Entity ( 0 , 0 , "workers" ) ;
var station = Entity ( 1 , 0 , "workers" ) ;
station . Kind = "station" ;
tug . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Tow ] ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 , Entities = [ tug , station ] ,
Orbits = [ new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "parent-orbit" , FixedPositionX = 20 } ] ,
Bodies = [ new AetheriaRuntimeBodySnapshotCommit { BodyKey = "parent-body" , Kind = "planet" , OrbitKey = "parent-orbit" } ]
} ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
2026-07-11 19:54:39 +01:00
CurrentZoneIndex = 0 , CurrentEntityKey = "" , Zones = [ zone ] ,
2026-07-11 18:53:20 +01:00
AgentTasks = [ new AetheriaRuntimeAgentTaskCommit { TaskId = "tow-1" , CorporationKey = "workers" , TaskType = AetheriaRuntimeAgentTaskTypes . Tow , ZoneIndex = 0 , Status = AetheriaRuntimeAgentTaskStatuses . Queued , TargetEntityIndex = 1 , OrbitParentKey = "parent-body" , OrbitDistance = 20 , CompletionRadius = 5 } ]
} ;
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-tow-attach-smoke.cc" ) , run ,
2026-07-15 03:52:56 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = NewPhysics ( ) , FrameId = 1 , FixedDeltaSeconds = 0.1 , SimulationTimeSeconds = 1 , BuildPublications = false } ) ;
2026-07-11 18:53:20 +01:00
Require ( run . Zones [ 0 ] . Entities [ 0 ] . ChildEntityIndices . Contains ( 1 ) , "tow pickup must attach station to tug parentage" ) ;
RequireEqual ( "" , run . Zones [ 0 ] . Entities [ 1 ] . OrbitKey , "attached station must no longer own an orbit" ) ;
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-tow-detach-smoke.cc" ) , run ,
2026-07-15 03:52:56 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = NewPhysics ( ) , FrameId = 2 , FixedDeltaSeconds = 0.1 , SimulationTimeSeconds = 2 , BuildPublications = false } ) ;
2026-07-11 18:53:20 +01:00
Require ( ! run . Zones [ 0 ] . Entities [ 0 ] . ChildEntityIndices . Contains ( 1 ) , "tow delivery must detach station parentage" ) ;
Require ( ! string . IsNullOrWhiteSpace ( run . Zones [ 0 ] . Entities [ 1 ] . OrbitKey ) , "delivered station must own a persistent orbit" ) ;
Require ( run . Zones [ 0 ] . Orbits . Any ( orbit = > orbit . OrbitKey = = run . Zones [ 0 ] . Entities [ 1 ] . OrbitKey & & orbit . ParentOrbitKey = = "parent-orbit" & & Math . Abs ( orbit . Distance - 20 ) < 0.001 ) ,
"delivered orbit must preserve requested parent and radius" ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Completed , run . AgentTasks [ 0 ] . Status , "tow task must complete only after detach applies" ) ;
2026-07-11 18:49:59 +01:00
}
private static void AgentSurveysBodyIntoCorporationKnowledge ( )
{
var surveyor = Entity ( 0 , 0 , "workers" ) ;
surveyor . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Explore ] ;
surveyor . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "scanner" , Enabled = true } } ] ;
var scanner = CatalogItem ( "scanner" , new AetheriaRuntimeBehaviorPayload ( 0 , "ResourceScanner" , 0 ,
[new AetheriaRuntimeBehaviorField(1, PerformanceStat(100)), new AetheriaRuntimeBehaviorField(2, PerformanceStat(4)), new AetheriaRuntimeBehaviorField(3, PerformanceStat(0.5))] ) ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ scanner ] , [ ] , [ ] ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
2026-07-11 19:54:39 +01:00
CurrentZoneIndex = 0 , CurrentEntityKey = "" ,
2026-07-11 18:49:59 +01:00
Zones = [ new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 , Entities = [ surveyor ] ,
Orbits = [ new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "survey-orbit" , FixedPositionX = 10 } ] ,
Bodies = [ new AetheriaRuntimeBodySnapshotCommit { BodyKey = "survey-world" , Kind = "planet" , OrbitKey = "survey-orbit" } ]
} ] ,
AgentTasks = [ new AetheriaRuntimeAgentTaskCommit { TaskId = "survey-1" , CorporationKey = "workers" , TaskType = AetheriaRuntimeAgentTaskTypes . Explore , ZoneIndex = 0 , Status = AetheriaRuntimeAgentTaskStatuses . Queued , TargetBodyKeys = [ "survey-world" ] } ]
} ;
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-survey-smoke.cc" ) , run ,
2026-07-15 03:52:56 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = NewPhysics ( ) , FrameId = 1 , FixedDeltaSeconds = 1 , SimulationTimeSeconds = 1 , Catalog = catalog , BuildPublications = false } ) ;
2026-07-11 18:49:59 +01:00
var knowledge = run . CorporationSurveys . Single ( ) ;
RequireEqual ( "workers" , knowledge . CorporationKey , "survey knowledge must belong to the agent corporation" ) ;
RequireEqual ( "survey-world" , knowledge . BodyKey , "survey knowledge must identify the scanned body" ) ;
RequireNear ( 4 , knowledge . DensityFloor , 0.000001 , "survey must publish the scanner minimum density" ) ;
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-survey-complete-smoke.cc" ) , run ,
2026-07-15 03:52:56 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = NewPhysics ( ) , FrameId = 2 , FixedDeltaSeconds = 1 , SimulationTimeSeconds = 2 , Catalog = catalog , BuildPublications = false } ) ;
2026-07-11 18:49:59 +01:00
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Completed , run . AgentTasks [ 0 ] . Status ,
"survey order must complete when corporation knowledge satisfies the scanner threshold" ) ;
2026-07-11 18:44:19 +01:00
}
private static void CargoCapacityComesFromHullAndCatalogVolumes ( )
{
var hull = CatalogItem ( "hauler-hull" ) ;
hull . HullCapacity = PerformanceStat ( 20 ) ;
var gear = CatalogItem ( "scanner" ) ;
gear . Volume = 3 ;
2026-07-15 03:52:56 +01:00
var cargoBay = CatalogItem ( "hauler-cargo" ) ;
cargoBay . Volume = 0 ;
cargoBay . InteriorOccupiedCells = 16 ;
2026-07-11 18:44:19 +01:00
var ore = CatalogItem ( "ore" ) ;
ore . Volume = 2 ;
2026-07-15 03:52:56 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , gear , cargoBay , ore ] , [ ] , [ ] ) ;
2026-07-11 18:44:19 +01:00
var entity = Entity ( 0 , 0 , "workers" ) ;
entity . HullItemKey = hull . ItemKey ;
2026-07-15 03:52:56 +01:00
entity . Equipment =
[
2026-07-17 00:46:58 +01:00
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = gear . ItemKey } }
2026-07-15 03:52:56 +01:00
] ;
2026-07-17 00:46:58 +01:00
entity . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey } } ] ;
2026-07-11 18:44:19 +01:00
entity . CargoContents = [ new AetheriaRuntimeCargoBayLoadoutCommit { Items = [ new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = ore . ItemKey , Quantity = 4 } } ] } ] ;
RequireNear ( 20 , AetheriaRuntimeCargoCapacityQueries . Capacity ( entity , catalog ) , 0.000001 ,
"cargo capacity must evaluate the authored hull performance stat" ) ;
RequireNear ( 11 , AetheriaRuntimeCargoCapacityQueries . Occupied ( entity , catalog ) , 0.000001 ,
"equipment and stacked cargo must consume catalog volume" ) ;
RequireEqual ( 4 , AetheriaRuntimeCargoCapacityQueries . UnitsThatFit ( entity , catalog , ore . ItemKey ) ,
2026-07-15 03:52:56 +01:00
"the installed cargo bay's remaining volume must determine whole units that fit" ) ;
2026-07-11 18:40:40 +01:00
}
private static void AgentMinesAsteroidThroughEquippedBehavior ( )
{
var miner = Entity ( 0 , 0 , "workers" ) ;
2026-07-11 18:46:36 +01:00
var home = Entity ( 1 , 0 , "workers" ) ;
2026-07-11 18:40:40 +01:00
miner . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Mine ] ;
2026-07-15 03:52:56 +01:00
miner . Equipment =
[
2026-07-17 00:46:58 +01:00
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "mining-tool" , Enabled = true , Quality = 1 , Durability = 1 } }
2026-07-15 03:52:56 +01:00
] ;
2026-07-17 00:46:58 +01:00
miner . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "miner-cargo" , Enabled = true , Quality = 1 , Durability = 1 } } ] ;
home . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "home-cargo" , Enabled = true , Quality = 1 , Durability = 1 } } ] ;
2026-07-11 18:46:36 +01:00
var minerHull = CatalogItem ( "miner-hull" ) ;
2026-07-15 03:52:56 +01:00
minerHull . HullCapacity = PerformanceStat ( 3 ) ;
2026-07-11 18:46:36 +01:00
var homeHull = CatalogItem ( "home-hull" ) ;
homeHull . HullCapacity = PerformanceStat ( 100 ) ;
var iron = CatalogItem ( "iron" ) ;
iron . SimpleCommodityCategory = "ore" ;
2026-07-17 00:56:01 +01:00
iron . Category = AetheriaRuntimeItemCategories . SimpleCommodity ;
iron . ShapeWidth = 1 ;
iron . ShapeHeight = 1 ;
iron . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
iron . Stackable = true ;
iron . MaxStack = 100 ;
2026-07-11 18:46:36 +01:00
iron . Volume = 1 ;
2026-07-15 03:52:56 +01:00
var minerCargo = CatalogItem ( "miner-cargo" ) ;
2026-07-17 00:56:01 +01:00
minerCargo . Category = AetheriaRuntimeItemCategories . CargoBay ;
minerCargo . ShapeWidth = 1 ;
minerCargo . ShapeHeight = 1 ;
minerCargo . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
minerCargo . InteriorShapeWidth = 2 ;
minerCargo . InteriorShapeHeight = 1 ;
2026-07-15 03:52:56 +01:00
minerCargo . InteriorOccupiedCells = 2 ;
2026-07-17 00:56:01 +01:00
minerCargo . InteriorShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) , new AetheriaRuntimeShapeCell ( 1 , 0 ) ] ;
2026-07-15 03:52:56 +01:00
var homeCargo = CatalogItem ( "home-cargo" ) ;
2026-07-17 00:56:01 +01:00
homeCargo . Category = AetheriaRuntimeItemCategories . CargoBay ;
homeCargo . ShapeWidth = 1 ;
homeCargo . ShapeHeight = 1 ;
homeCargo . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
homeCargo . InteriorShapeWidth = 10 ;
homeCargo . InteriorShapeHeight = 10 ;
2026-07-15 03:52:56 +01:00
homeCargo . InteriorOccupiedCells = 100 ;
2026-07-17 00:56:01 +01:00
homeCargo . InteriorShapeCells = Enumerable . Range ( 0 , 10 )
. SelectMany ( y = > Enumerable . Range ( 0 , 10 ) . Select ( x = > new AetheriaRuntimeShapeCell ( x , y ) ) )
. ToArray ( ) ;
2026-07-11 18:46:36 +01:00
miner . HullItemKey = minerHull . ItemKey ;
home . HullItemKey = homeHull . ItemKey ;
miner . CargoContents = [ new AetheriaRuntimeCargoBayLoadoutCommit ( ) ] ;
home . CargoContents = [ new AetheriaRuntimeCargoBayLoadoutCommit ( ) ] ;
2026-07-11 18:40:40 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot (
2026-07-15 03:52:56 +01:00
[ minerHull , homeHull , iron , minerCargo , homeCargo , CatalogItem ( "mining-tool" , new AetheriaRuntimeBehaviorPayload ( 0 , "MiningTool" , 0 ,
2026-07-11 18:40:40 +01:00
[new AetheriaRuntimeBehaviorField(1, PerformanceStat(1000)), new AetheriaRuntimeBehaviorField(2, PerformanceStat(1000000000)), new AetheriaRuntimeBehaviorField(3, PerformanceStat(2)), new AetheriaRuntimeBehaviorField(4, PerformanceStat(1000))] ) ) ] ,
[] , [ ] ) ;
var asteroid = new AetheriaRuntimeAsteroidCommit { Distance = 0 , Size = 6 } ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
2026-07-11 18:46:36 +01:00
Entities = [ miner , home ] ,
2026-07-11 18:40:40 +01:00
Bodies = [ new AetheriaRuntimeBodySnapshotCommit { BodyKey = "belt" , Kind = "asteroid_belt" , Asteroids = [ asteroid ] , Resources = [ new AetheriaRuntimeBodyResourceCommit { ItemKey = "iron" , Amount = 1 } ] } ]
} ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
GenerationSeed = 7 ,
CurrentZoneIndex = 0 ,
2026-07-11 19:54:39 +01:00
CurrentEntityKey = "" ,
2026-07-11 18:40:40 +01:00
Zones = [ zone ] ,
2026-07-11 18:46:36 +01:00
AgentTasks = [ new AetheriaRuntimeAgentTaskCommit { TaskId = "mine-1" , CorporationKey = "workers" , TaskType = AetheriaRuntimeAgentTaskTypes . Mine , ZoneIndex = 0 , OriginEntityIndex = 1 , CompletionRadius = 10 , Status = AetheriaRuntimeAgentTaskStatuses . Queued , TargetBodyKeys = [ "belt" ] } ]
2026-07-11 18:40:40 +01:00
} ;
var result = AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-mining-smoke.cc" ) , run ,
2026-07-15 03:52:56 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = NewPhysics ( ) , FrameId = 1 , FixedDeltaSeconds = 1 , SimulationTimeSeconds = 1 , Catalog = catalog , BuildPublications = false } ) ;
2026-07-11 18:40:40 +01:00
Require ( run . AgentTasks [ 0 ] . Phase = = "mining" , "mining task must activate its equipped tool" ) ;
Require ( result . OperationResult . Intents . Behaviors . Count = = 1 ,
2026-07-15 03:52:56 +01:00
$"mining behavior command must become daemon intent (count={result.OperationResult.Intents.Behaviors.Count}, applied={string.Join(',', result.Frame.AppliedCommandIds)}, rejected={string.Join(',', result.Frame.RejectedCommandIds)})" ) ;
2026-07-11 18:40:40 +01:00
var committedMiner = run . Zones [ 0 ] . Entities . Single ( entity = > entity . EntityIndex = = 0 ) ;
var committedAsteroid = run . Zones [ 0 ] . Bodies [ 0 ] . Asteroids [ 0 ] ;
Require ( committedAsteroid . RespawnTimer > 0 , $"mining damage must deplete the asteroid and start historical respawn (damage={committedAsteroid.Damage}, respawn={committedAsteroid.RespawnTimer})" ) ;
Require ( committedMiner . CargoContents . SelectMany ( bay = > bay . Items ) . Any ( slot = > slot . Item . ItemKey = = "iron" & & slot . Item . Quantity > 0 ) ,
"historical mining yield must enter daemon-owned cargo" ) ;
2026-07-11 18:46:36 +01:00
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-mining-offload-smoke.cc" ) , run ,
2026-07-15 03:52:56 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = NewPhysics ( ) , FrameId = 2 , FixedDeltaSeconds = 1 , SimulationTimeSeconds = 2 , Catalog = catalog , BuildPublications = false } ) ;
2026-07-11 18:46:36 +01:00
Require ( ! run . Zones [ 0 ] . Entities [ 0 ] . CargoContents . SelectMany ( bay = > bay . Items ) . Any ( ) ,
"full miner must offload through the shared cargo transfer command" ) ;
Require ( run . Zones [ 0 ] . Entities [ 1 ] . CargoContents . SelectMany ( bay = > bay . Items ) . Any ( slot = > slot . Item . ItemKey = = "iron" & & slot . Item . Quantity = = 1 ) ,
"home storage must receive the mined commodity" ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Assigned , run . AgentTasks [ 0 ] . Status ,
"miner must remain assigned after a successful offload" ) ;
2026-07-11 18:28:07 +01:00
}
2026-07-11 18:33:11 +01:00
private static void TickReconcilesAndEvaluatesCatalogBehaviors ( )
{
var entity = Entity ( 0 , 0 , "workers" ) ;
entity . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = "mining-tool" ,
Quality = 1 ,
Durability = 1 ,
Enabled = true
}
}
] ;
entity . BehaviorStates = Array . Empty < AetheriaRuntimeBehaviorStateCommit > ( ) ;
var payload = new AetheriaRuntimeBehaviorPayload (
0 ,
"MiningTool" ,
0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 12 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 0.8 ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , PerformanceStat ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 4 , PerformanceStat ( 50 ) )
] ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot (
[CatalogItem("mining-tool", payload)] ,
Array . Empty < AetheriaRuntimeCorporation > ( ) ,
Array . Empty < AetheriaRuntimeNameFile > ( ) ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "behavior-query-smoke" ,
CurrentZoneIndex = 0 ,
2026-07-11 19:54:39 +01:00
CurrentEntityKey = "" ,
2026-07-11 18:33:11 +01:00
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ]
} ;
AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-behavior-query-smoke.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
2026-07-15 03:52:56 +01:00
WorldPhysics = NewPhysics ( ) ,
2026-07-11 18:33:11 +01:00
FrameId = 1 ,
FixedDeltaSeconds = 0 ,
Catalog = catalog ,
BuildPublications = false
} ) ;
var behavior = AetheriaRuntimeEquippedBehaviorQueries . Find ( entity , catalog , "MiningTool" ) . Single ( ) ;
RequireEqual ( "MiningTool" , behavior . State . BehaviorKind ,
"tick must reconcile equipped catalog payloads into persistent behavior state" ) ;
RequireNear ( 12 , behavior . EvaluateStat ( 1 ) , 0.000001 , "behavior query must evaluate mining damage from catalog" ) ;
RequireNear ( 50 , behavior . EvaluateStat ( 4 ) , 0.000001 , "behavior query must evaluate mining range from catalog" ) ;
}
2026-07-11 20:32:33 +01:00
private static void DaemonLoadoutsRespectFactionAvailabilityAndHullRoles ( )
{
var cells4 = Enumerable . Range ( 0 , 4 ) . SelectMany ( y = > Enumerable . Range ( 0 , 4 )
. Select ( x = > new AetheriaRuntimeShapeCell ( x , y ) ) ) . ToArray ( ) ;
var one = new [ ] { new AetheriaRuntimeShapeCell ( 0 , 0 ) } ;
2026-07-13 16:53:25 +01:00
var cells2 = Enumerable . Range ( 0 , 2 ) . SelectMany ( y = > Enumerable . Range ( 0 , 2 )
. Select ( x = > new AetheriaRuntimeShapeCell ( x , y ) ) ) . ToArray ( ) ;
2026-07-11 20:32:33 +01:00
AetheriaRuntimeCatalogItem Item ( string key , string category , string manufacturer , int price ,
string hardpointType = "" , params string [ ] behaviors )
{
var item = CatalogItem ( key , behaviors . Select ( ( kind , index ) = >
new AetheriaRuntimeBehaviorPayload ( index , kind , 0 , Array . Empty < AetheriaRuntimeBehaviorField > ( ) ) ) . ToArray ( ) ) ;
item . Category = category ; item . ManufacturerKey = manufacturer ; item . Price = price ;
item . HardpointType = hardpointType ; item . ShapeWidth = 1 ; item . ShapeHeight = 1 ;
item . OccupiedCells = 1 ; item . ShapeCells = one ; item . BehaviorKinds = behaviors ;
return item ;
}
var availableHull = Item ( "available-hull" , AetheriaRuntimeItemCategories . Hull , "forge" , 100 ) ;
availableHull . HardpointType = "Hull" ;
availableHull . HullType = "Ship" ; availableHull . ShapeWidth = 4 ; availableHull . ShapeHeight = 4 ;
availableHull . OccupiedCells = 16 ; availableHull . ShapeCells = cells4 ;
availableHull . Hardpoints =
[
new AetheriaRuntimeHardpoint ( "ControlModule" , 0 , 0 , 1 , 1 , 1 , one , "" , "None" , 0 ) ,
2026-07-16 15:02:01 +01:00
new AetheriaRuntimeHardpoint ( "Weapon" , 1 , 0 , 1 , 1 , 1 , one , "" , "Clockwise" , 0 ) ,
2026-07-13 16:53:25 +01:00
new AetheriaRuntimeHardpoint ( "Sensors" , 2 , 0 , 1 , 1 , 1 , one , "" , "None" , 0 )
2026-07-11 20:32:33 +01:00
] ;
var unavailableHull = Item ( "cheap-foreign-hull" , AetheriaRuntimeItemCategories . Hull , "foreign" , 1 ) ;
unavailableHull . HardpointType = "Hull" ;
unavailableHull . HullType = "Ship" ; unavailableHull . ShapeWidth = 4 ; unavailableHull . ShapeHeight = 4 ;
unavailableHull . OccupiedCells = 16 ; unavailableHull . ShapeCells = cells4 ;
2026-07-11 20:34:40 +01:00
var stationHull = Item ( "station-hull" , AetheriaRuntimeItemCategories . Hull , "forge" , 120 ) ;
stationHull . HardpointType = "Hull" ; stationHull . HullType = "Station" ;
stationHull . ShapeWidth = 4 ; stationHull . ShapeHeight = 4 ; stationHull . OccupiedCells = 16 ;
stationHull . ShapeCells = cells4 ;
stationHull . Hardpoints =
[
2026-07-13 16:53:25 +01:00
new AetheriaRuntimeHardpoint ( "ControlModule" , 0 , 0 , 1 , 1 , 1 , one , "" , "None" , 0 ) ,
new AetheriaRuntimeHardpoint ( "Sensors" , 1 , 1 , 2 , 2 , 4 , cells2 , "" , "None" , 0 )
2026-07-11 20:34:40 +01:00
] ;
2026-07-11 20:32:33 +01:00
var cockpit = Item ( "cockpit" , AetheriaRuntimeItemCategories . Gear , "forge" , 20 , "ControlModule" , "Cockpit" ) ;
var wrongController = Item ( "cheap-turret-controller" , AetheriaRuntimeItemCategories . Gear , "forge" , 1 ,
"ControlModule" , "TurretController" ) ;
var weapon = Item ( "cannon" , AetheriaRuntimeItemCategories . Weapon , "forge" , 40 , "Weapon" , "LockWeapon" ) ;
2026-07-13 16:53:25 +01:00
var shipSensor = Item ( "ship-sensor" , AetheriaRuntimeItemCategories . Gear , "forge" , 15 , "Sensors" , "Sensor" ) ;
var stationSensor = Item ( "station-sensor" , AetheriaRuntimeItemCategories . Gear , "forge" , 80 , "Sensors" , "Sensor" ) ;
stationSensor . ShapeWidth = 2 ; stationSensor . ShapeHeight = 2 ;
stationSensor . OccupiedCells = 4 ; stationSensor . ShapeCells = cells2 ;
2026-07-11 20:32:33 +01:00
var cargo = Item ( "cargo-bay" , AetheriaRuntimeItemCategories . CargoBay , "forge" , 30 ) ;
cargo . HardpointType = "Internal" ;
2026-07-13 16:53:25 +01:00
cargo . InteriorShapeWidth = 3 ; cargo . InteriorShapeHeight = 3 ; cargo . InteriorOccupiedCells = 9 ;
cargo . InteriorShapeCells = Enumerable . Range ( 0 , 3 ) . SelectMany ( y = > Enumerable . Range ( 0 , 3 )
. Select ( x = > new AetheriaRuntimeShapeCell ( x , y ) ) ) . ToArray ( ) ;
2026-07-11 20:34:40 +01:00
var docking = Item ( "docking-bay" , AetheriaRuntimeItemCategories . DockingBay , "forge" , 35 ) ;
docking . HardpointType = "Internal" ;
2026-07-11 20:32:33 +01:00
var capacitor = Item ( "capacitor" , AetheriaRuntimeItemCategories . Gear , "forge" , 25 , "" , "Capacitor" ) ;
capacitor . HardpointType = "Internal" ;
var faction = new AetheriaRuntimeCorporation ( "forge" , "Forge" , "F" , "" , "" , "" , 1 , 1 ,
[new AetheriaRuntimeCorporationAllegiance("forge", 1)] ) ;
2026-07-11 20:38:48 +01:00
var foreign = new AetheriaRuntimeCorporation ( "foreign" , "Foreign" , "X" , "" , "" , "" , 1 , 2 ,
[new AetheriaRuntimeCorporationAllegiance("foreign", 1), new AetheriaRuntimeCorporationAllegiance("forge", 0.5)] ) ;
2026-07-13 16:53:25 +01:00
var reactor = Item ( "reactor" , AetheriaRuntimeItemCategories . Gear , "forge" , 25 , "" , "Reactor" ) ;
reactor . HardpointType = "Internal" ;
2026-07-11 20:32:33 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot (
2026-07-13 16:53:25 +01:00
[availableHull, unavailableHull, stationHull, cockpit, wrongController, weapon, shipSensor, stationSensor, cargo, docking, capacitor, reactor] ,
[faction, foreign] , Array . Empty < AetheriaRuntimeNameFile > ( ) ) ;
var fallbackCatalog = new AetheriaRuntimeCatalogSnapshot (
[availableHull, unavailableHull, stationHull, cockpit, wrongController, weapon, shipSensor, cargo, docking, capacitor, reactor] ,
2026-07-11 20:32:33 +01:00
[faction, foreign] , Array . Empty < AetheriaRuntimeNameFile > ( ) ) ;
var homes = new Dictionary < string , int > { [ "forge" ] = 0 , [ "foreign" ] = 1 } ;
var adjacency = new Dictionary < int , IReadOnlyList < int > > { [ 0 ] = [ 1 ] , [ 1 ] = [ 0 ] } ;
2026-07-16 17:27:01 +01:00
var rareHull = Item ( "rare-hull" , AetheriaRuntimeItemCategories . Hull , "forge" , 100 ) ;
rareHull . HardpointType = availableHull . HardpointType ;
rareHull . HullType = availableHull . HullType ;
rareHull . ShapeWidth = availableHull . ShapeWidth ;
rareHull . ShapeHeight = availableHull . ShapeHeight ;
rareHull . OccupiedCells = availableHull . OccupiedCells ;
rareHull . ShapeCells = availableHull . ShapeCells ;
rareHull . Hardpoints = availableHull . Hardpoints ;
rareHull . Tags = [ "rarity:rare" ] ;
var rarityCatalog = new AetheriaRuntimeCatalogSnapshot (
[availableHull, rareHull, cockpit, wrongController, weapon, shipSensor, cargo, capacitor, reactor] ,
[faction] , Array . Empty < AetheriaRuntimeNameFile > ( ) ) ;
2026-07-16 03:47:28 +01:00
var first = new AetheriaDaemonLoadoutGenerator ( catalog , 42 , 0 , homes , adjacency ) . Build ( "ship" , "forge" ) ;
var second = new AetheriaDaemonLoadoutGenerator ( catalog , 42 , 0 , homes , adjacency ) . Build ( "ship" , "forge" ) ;
var station = new AetheriaDaemonLoadoutGenerator ( catalog , 84 , 0 , homes , adjacency ) . Build ( "station" , "forge" ) ;
2026-07-13 16:53:25 +01:00
var fallbackStation = new AetheriaDaemonLoadoutGenerator ( fallbackCatalog , 84 , 0 , homes , adjacency )
2026-07-16 03:47:28 +01:00
. Build ( "station" , "forge" ) ;
2026-07-11 20:38:48 +01:00
var uninterruptedForge = new AetheriaDaemonLoadoutGenerator ( catalog , 101 , 0 , homes , adjacency ) ;
var interleavedForge = new AetheriaDaemonLoadoutGenerator ( catalog , 101 , 0 , homes , adjacency ) ;
var foreignStream = new AetheriaDaemonLoadoutGenerator ( catalog , 202 , 1 , homes , adjacency ) ;
var uninterruptedSequence = new [ ]
{
2026-07-16 03:47:28 +01:00
uninterruptedForge . Build ( "ship" , "forge" ) ,
uninterruptedForge . Build ( "ship" , "forge" )
2026-07-11 20:38:48 +01:00
} ;
2026-07-16 03:47:28 +01:00
var interleavedFirst = interleavedForge . Build ( "ship" , "forge" ) ;
foreignStream . Build ( "ship" , "foreign" ) ;
var interleavedSecond = interleavedForge . Build ( "ship" , "forge" ) ;
2026-07-16 17:27:01 +01:00
var rarityGenerator = new AetheriaDaemonLoadoutGenerator (
rarityCatalog , 9001 , 0 , homes , adjacency ) ;
var rareSelections = Enumerable . Range ( 0 , 2000 )
. Select ( _ = > rarityGenerator . Build ( "ship" , "forge" ) . HullItemKey )
. Count ( key = > key = = "rare-hull" ) ;
2026-07-11 20:32:33 +01:00
RequireEqual ( "available-hull" , first . HullItemKey ,
"loadout generation must exclude manufacturers outside the faction allegiance graph" ) ;
Require ( first . Equipment . Any ( value = > value . ItemKey = = "cockpit" ) & &
first . Equipment . All ( value = > value . ItemKey ! = "cheap-turret-controller" ) ,
"ship control hardpoints must require the cockpit role even when the wrong controller is cheaper" ) ;
Require ( first . Equipment . Any ( value = > value . ItemKey = = "cannon" ) & &
2026-07-17 00:46:58 +01:00
first . CargoBays . Any ( value = > value . ItemKey = = "cargo-bay" ) & &
2026-07-13 16:53:25 +01:00
first . Equipment . Any ( value = > value . ItemKey = = "capacitor" ) & &
first . Equipment . Any ( value = > value . ItemKey = = "ship-sensor" ) & &
first . Equipment . All ( value = > value . ItemKey ! = "station-sensor" ) ,
"generated ships must fit hardpoint equipment and reject station-sized sensor gear" ) ;
2026-07-16 15:02:01 +01:00
RequireEqual ( "Clockwise" , first . Equipment . Single ( value = > value . ItemKey = = "cannon" ) . Rotation ,
"generated equipment must preserve the placement rotation used by hardpoint fitting" ) ;
2026-07-11 20:32:33 +01:00
Require ( first . HullItemKey = = second . HullItemKey & &
first . Equipment . Select ( value = > value . ItemKey ) . SequenceEqual ( second . Equipment . Select ( value = > value . ItemKey ) ) ,
"same seed, map, faction and catalog must produce the same loadout" ) ;
2026-07-16 03:47:28 +01:00
Require ( first . Cargo . Length = = 0 & & first . Receipt . Selections . All ( value = > value . Role ! = "cargo" ) ,
"ordinary generated ships must not acquire cargo from non-canonical scenario aliases" ) ;
2026-07-11 20:37:09 +01:00
Require ( first . Receipt . Seed = = 42 & & first . Receipt . SourceZoneIndex = = 0 & &
first . Receipt . AvailabilityFactionKey = = "forge" & &
first . Receipt . Selections . Any ( value = > value . Role = = "hull" & & value . ItemKey = = "available-hull" & &
value . ManufacturerKey = = "forge" & & value . ManufacturerDistance = = 1 & & value . Allegiance = = 1 ) ,
"generated loadouts must carry daemon-authored source and selection provenance" ) ;
2026-07-16 17:27:01 +01:00
Require ( rareSelections > 0 & & rareSelections < 200 ,
$"rare catalog candidates must remain possible without becoming a default loadout path (selected {rareSelections}/2000)" ) ;
2026-07-17 00:46:58 +01:00
Require ( station . DockingBays . Any ( value = > value . ItemKey = = "docking-bay" ) & &
station . CargoBays . Any ( value = > value . ItemKey = = "cargo-bay" ) & &
2026-07-11 20:34:40 +01:00
station . Equipment . Any ( value = > value . ItemKey = = "capacitor" ) & &
2026-07-13 16:53:25 +01:00
station . Equipment . Any ( value = > value . ItemKey = = "cheap-turret-controller" ) & &
station . Equipment . Any ( value = > value . ItemKey = = "station-sensor" ) & &
station . Equipment . All ( value = > value . ItemKey ! = "ship-sensor" ) ,
"station generation must fill a large sensor hardpoint with the largest available compatible array" ) ;
Require ( fallbackStation . Equipment . Any ( value = > value . ItemKey = = "ship-sensor" ) ,
"a smaller sensor must remain a valid fallback when it fits inside a larger same-type hardpoint" ) ;
Require ( station . Cargo . Length > 0 & & station . Cargo . Length < = cargo . InteriorOccupiedCells & &
2026-07-16 03:47:28 +01:00
station . Cargo . All ( value = > value . Item . ItemKey ! = "cheap-foreign-hull" & &
catalog . FindItem ( value . Item . ItemKey ) ! = null ) & &
station . Receipt . Selections . Where ( value = > value . Role = = "cargo" )
. Select ( value = > value . ItemKey )
. SequenceEqual ( station . Cargo . Select ( value = > value . Item . ItemKey ) ) ,
"station inventory draws must use canonical catalog keys, respect cargo capacity, exclude unavailable manufacturers, and preserve exact provenance" ) ;
2026-07-11 20:38:48 +01:00
Require ( LoadoutKeys ( uninterruptedSequence [ 0 ] ) . SequenceEqual ( LoadoutKeys ( interleavedFirst ) ) & &
LoadoutKeys ( uninterruptedSequence [ 1 ] ) . SequenceEqual ( LoadoutKeys ( interleavedSecond ) ) ,
"generation in another faction stream must not perturb this faction's continuing loadout sequence" ) ;
2026-07-11 20:32:33 +01:00
}
2026-07-11 20:38:48 +01:00
private static IEnumerable < string > LoadoutKeys ( AetheriaDaemonLoadout loadout ) = >
new [ ] { loadout . HullItemKey }
. Concat ( loadout . Equipment . Select ( value = > value . ItemKey ) )
2026-07-17 00:46:58 +01:00
. Concat ( loadout . CargoBays . Select ( value = > value . ItemKey ) )
. Concat ( loadout . DockingBays . Select ( value = > value . ItemKey ) )
2026-07-11 20:38:48 +01:00
. Concat ( loadout . Cargo . Select ( value = > value . Item . ItemKey ) ) ;
2026-07-11 18:33:11 +01:00
private static AetheriaRuntimeBehaviorValue PerformanceStat ( double value ) = > new (
"performance-stat" ,
"" ,
0 ,
false ,
"" ,
"" ,
[Number(value), Number(value), Number(0), Number(0), Number(0)] ,
Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ;
private static AetheriaRuntimeBehaviorValue Number ( double value ) = > new (
"number" ,
"" ,
value ,
false ,
"" ,
"" ,
Array . Empty < AetheriaRuntimeBehaviorValue > ( ) ,
Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ;
2026-07-17 02:55:07 +01:00
private static AetheriaRuntimeBehaviorValue StringValue ( string value ) = > new (
"string" , value , 0 , false , "" , "" ,
Array . Empty < AetheriaRuntimeBehaviorValue > ( ) ,
Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ;
2026-07-17 03:03:30 +01:00
private static AetheriaRuntimeBehaviorValue BoolValue ( bool value ) = > new (
"bool" , "" , 0 , value , "" , "" ,
Array . Empty < AetheriaRuntimeBehaviorValue > ( ) ,
Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ;
private static AetheriaRuntimeBehaviorValue ItemKeyValue ( string value ) = > new (
"item-key" , "" , 0 , false , "" , value ,
Array . Empty < AetheriaRuntimeBehaviorValue > ( ) ,
Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ;
2026-07-17 02:55:07 +01:00
private static AetheriaRuntimeBehaviorValue StatReference ( string target , string stat ) = > new (
"stat-reference" , "" , 0 , false , "" , "" ,
[StringValue(""), StringValue(target), StringValue(stat)] ,
Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ;
2026-07-16 15:47:38 +01:00
private static AetheriaRuntimeBehaviorValue Vector ( params double [ ] values ) = > new (
"float3" ,
"" ,
0 ,
false ,
"" ,
"" ,
values . Select ( Number ) . ToArray ( ) ,
Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ;
private static AetheriaRuntimeBehaviorValue Curve ( params AetheriaRuntimeCurveKey [ ] keys ) = > new (
"bezier-curve" ,
"" ,
0 ,
false ,
"" ,
"" ,
2026-07-16 16:26:42 +01:00
[ new AetheriaRuntimeBehaviorValue (
"array" ,
"" ,
0 ,
false ,
"" ,
"" ,
keys . Select ( key = > Vector ( key . Time , key . Value , key . InTangent , key . OutTangent ) ) . ToArray ( ) ,
Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ] ,
2026-07-16 15:47:38 +01:00
Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ;
private static AetheriaRuntimeBehaviorPayload AetherDrivePayload (
double couplingEfficiency = 1 ,
double energyDraw = 0 ) = > new (
0 ,
AetheriaRuntimeBehaviorKinds . AetherDrive ,
0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , Vector ( 100 , 100 , 100 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , Vector ( 10 , 10 , 0.1 ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , PerformanceStat ( 100 ) ) ,
new AetheriaRuntimeBehaviorField ( 4 , Vector ( 10 , 10 , 10 ) ) ,
new AetheriaRuntimeBehaviorField ( 5 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( couplingEfficiency ) ) ,
new AetheriaRuntimeBehaviorField ( 7 , PerformanceStat ( 10000 ) ) ,
new AetheriaRuntimeBehaviorField ( 8 , Curve (
new AetheriaRuntimeCurveKey ( 0 , 1 , 0 , 0 ) ,
new AetheriaRuntimeCurveKey ( 1 , 1 , 0 , 0 ) ) ) ,
new AetheriaRuntimeBehaviorField ( 9 , PerformanceStat ( energyDraw ) ) ,
new AetheriaRuntimeBehaviorField ( 10 , PerformanceStat ( 0 ) )
] ) ;
private static AetheriaRuntimeBehaviorPayload ThrusterPayload ( ) = > new (
0 ,
AetheriaRuntimeBehaviorKinds . Thruster ,
0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 90 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 4 , PerformanceStat ( 0 ) )
] ) ;
private static AetheriaRuntimeCatalogSnapshot EquipThrusterBank (
IEnumerable < AetheriaRuntimeEntitySnapshotCommit > entities ,
params AetheriaRuntimeCatalogItem [ ] additionalItems )
{
var hull = HullCatalogItem ( "smoke-standard-thruster-hull" , 5 , 5 , 0 ) ;
hull . HullDrag = 1 ;
var thruster = CatalogItem ( "smoke-directional-thruster" , ThrusterPayload ( ) ) ;
var placements = new [ ]
{
( 0 , 2 , "None" ) , ( 4 , 2 , "None" ) ,
( 0 , 1 , "Half" ) , ( 4 , 1 , "Half" ) ,
( 2 , 0 , "CounterClockwise" ) , ( 2 , 4 , "CounterClockwise" ) ,
( 1 , 0 , "Clockwise" ) , ( 1 , 4 , "Clockwise" )
} ;
foreach ( var entity in entities . Where ( entity = > entity . Kind = = "ship" ) )
{
if ( string . IsNullOrWhiteSpace ( entity . HullItemKey ) )
entity . HullItemKey = hull . ItemKey ;
entity . Equipment = ( entity . Equipment ? ? Array . Empty < AetheriaRuntimeLoadoutItemSlotCommit > ( ) )
. Concat ( placements . Select ( value = > new AetheriaRuntimeLoadoutItemSlotCommit
{
X = value . Item1 ,
Y = value . Item2 ,
Rotation = value . Item3 ,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = thruster . ItemKey ,
Quantity = 1 ,
Durability = 1 ,
Enabled = true
}
} ) )
. ToArray ( ) ;
}
return new AetheriaRuntimeCatalogSnapshot (
additionalItems . Concat ( [ hull , thruster ] ) . ToArray ( ) , [ ] , [ ] ) ;
}
private static AetheriaRuntimeCatalogSnapshot EquipAetherDrive (
IEnumerable < AetheriaRuntimeEntitySnapshotCommit > entities ,
params AetheriaRuntimeCatalogItem [ ] additionalItems )
{
var hull = HullCatalogItem ( "smoke-rare-aether-drive-hull" , 3 , 3 , 0 ) ;
hull . Hardpoints =
[
new AetheriaRuntimeHardpoint (
"AetherDrive" , 1 , 1 , 1 , 1 , 1 ,
[new AetheriaRuntimeShapeCell(0, 0)] , "" , "None" , 0 )
] ;
var drive = CatalogItem ( "smoke-aether-drive" , AetherDrivePayload ( ) ) ;
drive . HardpointType = "AetherDrive" ;
foreach ( var entity in entities . Where ( entity = > entity . Kind = = "ship" ) )
{
if ( string . IsNullOrWhiteSpace ( entity . HullItemKey ) )
entity . HullItemKey = hull . ItemKey ;
entity . Equipment = ( entity . Equipment ? ? Array . Empty < AetheriaRuntimeLoadoutItemSlotCommit > ( ) )
. Concat ( [ new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 1 ,
Y = 1 ,
Rotation = "None" ,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = drive . ItemKey ,
Quantity = 1 ,
Durability = 1 ,
Enabled = true
}
} ] )
. ToArray ( ) ;
}
return new AetheriaRuntimeCatalogSnapshot (
additionalItems . Concat ( [ hull , drive ] ) . ToArray ( ) , [ ] , [ ] ) ;
}
2026-07-12 06:01:14 +01:00
private static AetheriaRuntimeBehaviorPayload CapacitorPayload ( double capacity , double efficiency ) = > new (
0 , "Capacitor" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( capacity ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( efficiency ) )
] ) ;
2026-07-17 02:28:38 +01:00
private static AetheriaRuntimeBehaviorPayload SensorPayload (
double sensitivity = 1 ,
double pingBoost = 1 ,
double pingEnergy = 0 ,
double pingVisibility = 3 ,
double pingRange = 200 ,
double pingCooldown = 1 ,
double pingDuration = 2 ,
double pingRadiusExponent = 0.5 ) = > new (
0 , AetheriaRuntimeBehaviorKinds . Sensor , 0 ,
[
new AetheriaRuntimeBehaviorField ( 3 , PerformanceStat ( sensitivity ) ) ,
new AetheriaRuntimeBehaviorField ( 4 , Curve (
new AetheriaRuntimeCurveKey ( 0 , 1 , 0 , 0 ) ,
new AetheriaRuntimeCurveKey ( 1 , 1 , 0 , 0 ) ) ) ,
new AetheriaRuntimeBehaviorField ( 5 , PerformanceStat ( pingBoost ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( pingEnergy ) ) ,
new AetheriaRuntimeBehaviorField ( 7 , PerformanceStat ( pingVisibility ) ) ,
new AetheriaRuntimeBehaviorField ( 8 , PerformanceStat ( pingRange ) ) ,
new AetheriaRuntimeBehaviorField ( 9 , PerformanceStat ( pingCooldown ) ) ,
new AetheriaRuntimeBehaviorField ( 10 , Number ( pingDuration ) ) ,
new AetheriaRuntimeBehaviorField ( 11 , Number ( pingRadiusExponent ) )
] ) ;
2026-07-11 18:33:11 +01:00
private static AetheriaRuntimeCatalogItem CatalogItem ( string itemKey , params AetheriaRuntimeBehaviorPayload [ ] payloads ) = > new (
itemKey , itemKey , "equipment" , "" , "" , 0 , 1 , 1 , 1 , 1 ,
1 , 1 , 1 , Array . Empty < AetheriaRuntimeShapeCell > ( ) ,
0 , 0 , 0 , Array . Empty < AetheriaRuntimeShapeCell > ( ) ,
Array . Empty < AetheriaRuntimeHardpoint > ( ) , payloads ,
"utility" , "" , payloads . Select ( payload = > payload . Kind ) . ToArray ( ) ,
1 , false , 0 , 1 , "" , "" , "" , "" , "" ,
0 , 1000 , Array . Empty < AetheriaRuntimeCurveKey > ( ) , "" , 1 , 0 , 0 , 0 , false ,
0 , 0 , "" , Array . Empty < AetheriaRuntimeAudioStat > ( ) , Array . Empty < AetheriaRuntimeCurveKey > ( ) , "" , "" ) ;
2026-07-17 04:09:35 +01:00
private static AetheriaRuntimeCatalogItem WearableWeaponCatalogItem (
string itemKey , params AetheriaRuntimeBehaviorPayload [ ] payloads )
{
var item = CatalogItem ( itemKey , payloads ) ;
item . Durability = 1 ;
item . ThermalResilience = 1 ;
item . MinimumTemperature = 0 ;
item . MaximumTemperature = 1 ;
item . ThermalPerformanceCurveKeys =
[
new AetheriaRuntimeCurveKey ( 0 , 0.9 , 0 , 0 ) ,
new AetheriaRuntimeCurveKey ( 1 , 0.9 , 0 , 0 )
] ;
return item ;
}
2026-07-12 05:13:03 +01:00
private static AetheriaRuntimeCatalogItem HullCatalogItem ( string itemKey , int width , int height , double armor )
{
var cells = Enumerable . Range ( 0 , height )
. SelectMany ( y = > Enumerable . Range ( 0 , width ) . Select ( x = > new AetheriaRuntimeShapeCell ( x , y ) ) )
. ToArray ( ) ;
return new AetheriaRuntimeCatalogItem (
itemKey , itemKey , "hull" , "" , "" , 0 , 1 , 1 , 1 , 1 ,
width , height , cells . Length , cells ,
width , height , cells . Length , cells ,
Array . Empty < AetheriaRuntimeHardpoint > ( ) , Array . Empty < AetheriaRuntimeBehaviorPayload > ( ) ,
"" , "ship" , Array . Empty < string > ( ) ,
1 , false , 0 , 1 , "" , "" , "" , "" , "" ,
0 , 1000 , Array . Empty < AetheriaRuntimeCurveKey > ( ) , "" , 1 , 0 , armor , 0 , false ,
0 , 0 , "" , Array . Empty < AetheriaRuntimeAudioStat > ( ) , Array . Empty < AetheriaRuntimeCurveKey > ( ) , "" , "" ) ;
}
2026-07-12 05:32:03 +01:00
private static AetheriaRuntimeDaemonSimulationSettings LootSettings ( double probability )
{
var value = AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ;
return new AetheriaRuntimeDaemonSimulationSettings (
value . PawnSpeed , value . RaiderSpeed , value . AttackRange , value . AttackHoldRatio ,
value . PawnProjectileDamage , value . RaiderProjectileDamage , value . WeaponCooldownSeconds ,
value . ProjectileSpeed , value . ProjectileRadius , value . ProjectileLifetimeSeconds ,
value . ProjectileSpawnOffset , value . ProjectileHeatScale , value . HeatDissipationPerSecond ,
value . StationSensorRange , value . EntitySensorRange , value . PlayerStationHull ,
value . HostileStationHull , value . PlayerEntityHull , value . RaiderEntityHull ,
value . StationShield , value . EntityShield , value . WeaponLockSpeed ,
value . WeaponLockSensorImpact , value . WeaponLockAngleDegrees ,
value . WeaponLockDirectionImpact , value . WeaponLockDecayPerSecond ,
probability , value . LootDropVelocity , value . PickupLifetimeSeconds ) ;
}
2026-07-11 18:28:07 +01:00
private static void AgentPatrolsHistoricalOrbitCircuitThroughMovementCommands ( )
{
var agent = Entity ( 0 , 0 , "workers" ) ;
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Defend ] ;
2026-07-16 15:47:38 +01:00
var catalog = EquipThrusterBank ( [ agent ] ) ;
2026-07-11 18:28:07 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-patrol-smoke" ,
CurrentZoneIndex = 0 ,
2026-07-11 19:54:39 +01:00
CurrentEntityKey = "" ,
2026-07-11 18:28:07 +01:00
Zones =
[
new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ agent ] ,
Orbits =
[
new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:east" , FixedPositionX = 20 } ,
new AetheriaRuntimeOrbitSnapshotCommit { OrbitKey = "orbit:west" , FixedPositionX = - 20 }
] ,
Bodies =
[
new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:east" , OrbitKey = "orbit:east" , Kind = "planet" } ,
new AetheriaRuntimeBodySnapshotCommit { BodyKey = "body:west" , OrbitKey = "orbit:west" , Kind = "planet" }
]
}
]
} ;
var issue = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . IssueAgentTask ,
"commander-smoke" ,
"starbridge-smoke" ,
0 ,
"" ) ;
issue . CommandId = "issue-patrol" ;
issue . AgentTask = new AetheriaRuntimeAgentTaskCommand
{
TaskId = "patrol-orbits" ,
CorporationKey = "workers" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Defend ,
Priority = 10 ,
ZoneIndex = 0 ,
CompletionRadius = 5 ,
TargetBodyKeys = [ "body:east" , "body:west" ]
} ;
var sawWestLeg = false ;
var sawReturnToEast = false ;
2026-07-16 15:47:38 +01:00
var physics = NewPhysics ( ) ;
for ( var frame = 0 ; frame < 100 ; frame + + )
2026-07-11 18:28:07 +01:00
{
var tick = AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-agent-patrol-smoke.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
2026-07-16 15:47:38 +01:00
WorldPhysics = physics ,
Catalog = catalog ,
2026-07-11 18:28:07 +01:00
FrameId = frame ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = frame * 0.1 ,
ObservedCommands = frame = = 0 ? [ issue ] : Array . Empty < AetheriaRuntimeDaemonCommandDocument > ( ) ,
BuildPublications = false
} ) ;
Require ( tick . OperationResult . AppliedCommandIds . Any ( id = > id . EndsWith ( ":move" , StringComparison . Ordinal ) ) ,
"patrol controller must drive the shared movement command every tick" ) ;
var cursor = run . AgentTasks . Single ( ) . CircuitIndex ;
sawWestLeg | = cursor = = 1 ;
sawReturnToEast | = sawWestLeg & & cursor = = 0 ;
if ( sawReturnToEast )
break ;
}
Require ( sawWestLeg & & sawReturnToEast , "patrol must advance through and wrap its authored orbit circuit" ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Assigned , run . AgentTasks . Single ( ) . Status ,
"patrol is persistent work and must remain assigned after one circuit" ) ;
2026-07-11 18:09:43 +01:00
}
2026-07-11 18:19:03 +01:00
private static void RejectedHaulTransferDoesNotAdvanceTask ( )
{
var origin = Entity ( 0 , 0 , "workers" ) ;
origin . CargoContents = [ Cargo ( ( "ore" , 2 , 0 , 0 ) ) ] ;
var agent = Entity ( 1 , 0 , "workers" ) ;
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Haul ] ;
agent . CargoContents = Array . Empty < AetheriaRuntimeCargoBayLoadoutCommit > ( ) ;
var destination = Entity ( 2 , 20 , "workers" ) ;
destination . CargoContents = [ Cargo ( ) ] ;
var task = new AetheriaRuntimeAgentTaskCommit
{
TaskId = "rejected-haul" ,
CorporationKey = "workers" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Haul ,
Priority = 1 ,
ZoneIndex = 0 ,
OriginEntityIndex = 0 ,
TargetEntityIndex = 2 ,
ItemKey = "ore" ,
RequestedQuantity = 1 ,
CompletionRadius = 5 ,
Phase = "pickup"
} ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "rejected-haul-smoke" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ origin , agent , destination ] } ] ,
AgentTasks = [ task ]
} ;
var planned = AetheriaRuntimeAgentScheduler . AssignAndPlan ( run , 1 ) ;
var reduced = AetheriaRuntimeDaemonOperations . Execute ( run , planned ) ;
AetheriaRuntimeAgentScheduler . Reconcile ( run , 1 , reduced . AppliedCommandIds , reduced . RejectedCommandIds ) ;
Require ( reduced . RejectedCommandIds . Any ( id = > id . EndsWith ( ":pickup" , StringComparison . Ordinal ) ) ,
"invalid pickup must be rejected by the normal cargo reducer" ) ;
RequireEqual ( "pickup" , task . Phase , "rejected pickup must not advance the haul task" ) ;
RequireEqual ( 0 , task . PendingQuantity , "rejected pickup must clear pending transfer state" ) ;
RequireEqual ( 2 , CargoQuantity ( origin , "ore" ) , "rejected pickup must leave origin cargo untouched" ) ;
}
private static void AgentCompletesHaulTaskThroughMovementAndCargoCommands ( )
{
2026-07-17 00:56:01 +01:00
var cargoBay = CatalogItem ( "haul-cargo-bay" ) ;
cargoBay . Category = AetheriaRuntimeItemCategories . CargoBay ;
cargoBay . ShapeWidth = 1 ;
cargoBay . ShapeHeight = 1 ;
cargoBay . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
cargoBay . InteriorShapeWidth = 4 ;
cargoBay . InteriorShapeHeight = 4 ;
cargoBay . InteriorOccupiedCells = 16 ;
cargoBay . InteriorShapeCells = Enumerable . Range ( 0 , 4 )
. SelectMany ( y = > Enumerable . Range ( 0 , 4 ) . Select ( x = > new AetheriaRuntimeShapeCell ( x , y ) ) )
. ToArray ( ) ;
var ore = CatalogItem ( "ore" ) ;
ore . Category = AetheriaRuntimeItemCategories . SimpleCommodity ;
ore . ShapeWidth = 1 ;
ore . ShapeHeight = 1 ;
ore . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
ore . Stackable = true ;
ore . MaxStack = 100 ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ cargoBay , ore ] , [ ] , [ ] ) ;
AetheriaRuntimeLoadoutItemSlotCommit InstalledCargoBay ( ) = > new ( )
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
} ;
2026-07-11 18:19:03 +01:00
var origin = Entity ( 0 , 0 , "workers" ) ;
origin . Kind = "station" ;
2026-07-17 00:56:01 +01:00
origin . CargoBays = [ InstalledCargoBay ( ) ] ;
2026-07-11 18:19:03 +01:00
origin . CargoContents = [ Cargo ( ( "ore" , 5 , 2 , 3 ) ) ] ;
var agent = Entity ( 1 , 0 , "workers" ) ;
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Haul ] ;
2026-07-17 00:56:01 +01:00
agent . CargoBays = [ InstalledCargoBay ( ) ] ;
2026-07-11 18:19:03 +01:00
agent . CargoContents = [ Cargo ( ) ] ;
var destination = Entity ( 2 , 50 , "workers" ) ;
destination . Kind = "station" ;
2026-07-17 00:56:01 +01:00
destination . CargoBays = [ InstalledCargoBay ( ) ] ;
2026-07-11 18:19:03 +01:00
destination . CargoContents = [ Cargo ( ) ] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-haul-smoke" ,
CurrentZoneIndex = 0 ,
2026-07-11 19:54:39 +01:00
CurrentEntityKey = "" ,
2026-07-11 18:19:03 +01:00
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ origin , agent , destination ] } ]
} ;
var issue = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . IssueAgentTask ,
"commander-smoke" ,
"starbridge-smoke" ,
0 ,
"" ) ;
issue . CommandId = "issue-haul" ;
issue . AgentTask = new AetheriaRuntimeAgentTaskCommand
{
TaskId = "haul-ore" ,
CorporationKey = "workers" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Haul ,
Priority = 40 ,
ZoneIndex = 0 ,
OriginEntityIndex = 0 ,
TargetEntityIndex = 2 ,
ItemKey = "ore" ,
Quantity = 3 ,
CompletionRadius = 5
} ;
var sawPickup = false ;
var sawDelivery = false ;
for ( var frame = 0 ; frame < 30 ; frame + + )
{
var tick = AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-agent-haul-smoke.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
2026-07-15 03:52:56 +01:00
WorldPhysics = NewPhysics ( ) ,
2026-07-11 18:19:03 +01:00
FrameId = frame ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = frame * 0.1 ,
ObservedCommands = frame = = 0 ? [ issue ] : Array . Empty < AetheriaRuntimeDaemonCommandDocument > ( ) ,
2026-07-17 00:56:01 +01:00
Catalog = catalog ,
2026-07-11 18:19:03 +01:00
BuildPublications = false
} ) ;
sawPickup | = tick . OperationResult . AppliedCommandIds . Any ( id = > id . EndsWith ( ":pickup" , StringComparison . Ordinal ) ) ;
sawDelivery | = tick . OperationResult . AppliedCommandIds . Any ( id = > id . EndsWith ( ":delivery" , StringComparison . Ordinal ) ) ;
if ( string . Equals ( run . AgentTasks . Single ( ) . Status , AetheriaRuntimeAgentTaskStatuses . Completed , StringComparison . Ordinal ) )
break ;
}
Require ( sawPickup & & sawDelivery , "haul task must use accepted pickup and delivery cargo commands" ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Completed , run . AgentTasks . Single ( ) . Status ,
"haul task must complete only after accepted delivery" ) ;
RequireEqual ( 2 , CargoQuantity ( origin , "ore" ) , "origin must retain the unrequested stack quantity" ) ;
RequireEqual ( 3 , CargoQuantity ( destination , "ore" ) , "destination must receive exactly the requested quantity" ) ;
RequireEqual ( 0 , CargoQuantity ( agent , "ore" ) , "hauler must finish with no in-transit cargo" ) ;
}
private static AetheriaRuntimeCargoBayLoadoutCommit Cargo ( params ( string ItemKey , int Quantity , int X , int Y ) [ ] items ) = > new ( )
{
Items = items . Select ( item = > new AetheriaRuntimeLoadoutItemSlotCommit
{
X = item . X ,
Y = item . Y ,
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = item . ItemKey , Quantity = item . Quantity }
} ) . ToArray ( )
} ;
private static int CargoQuantity ( AetheriaRuntimeEntitySnapshotCommit entity , string itemKey ) = >
( entity . CargoContents ? ? Array . Empty < AetheriaRuntimeCargoBayLoadoutCommit > ( ) )
. SelectMany ( bay = > bay . Items )
. Where ( slot = > string . Equals ( slot . Item . ItemKey , itemKey , StringComparison . Ordinal ) )
. Sum ( slot = > slot . Item . Quantity ) ;
2026-07-11 18:09:43 +01:00
private static void AgentCompletesAttackTaskThroughTargetFireAndYmir ( )
{
var agent = Entity ( 0 , 0 , "player" ) ;
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Attack ] ;
agent . WeaponGroups = [ new [ ] { 0 } ] ;
2026-07-11 20:23:42 +01:00
agent . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = "test-lock-cannon" , Quality = 1 , Durability = 1 , Enabled = true
}
2026-07-12 06:01:14 +01:00
} ,
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
2026-07-17 02:28:38 +01:00
{ ItemKey = "test-attack-capacitor" , Quality = 1 , Durability = 1 , Enabled = true } } ,
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "test-attack-sensor" , Quality = 1 , Durability = 1 , Enabled = true } }
2026-07-11 20:23:42 +01:00
] ;
2026-07-11 20:45:01 +01:00
agent . BehaviorStates =
[
new AetheriaRuntimeBehaviorStateCommit
{
2026-07-12 06:01:14 +01:00
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind , OwnerIndex = 1 , BehaviorIndex = 0 ,
2026-07-11 20:45:01 +01:00
BehaviorKind = "Capacitor" , CapacitorCharge = 50 , CapacitorCapacity = 50 , CapacitorEfficiency = 1
}
] ;
agent . CargoContents = [ Cargo ( ( "test-ammo" , 2 , 0 , 0 ) ) ] ;
2026-07-11 20:23:42 +01:00
var weaponPayload = new AetheriaRuntimeBehaviorPayload (
0 ,
"LockWeapon" ,
0 ,
[
2026-07-12 05:13:03 +01:00
new AetheriaRuntimeBehaviorField ( 1 , Number ( 1 ) ) ,
2026-07-11 20:23:42 +01:00
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 7 ) ) ,
2026-07-12 05:13:03 +01:00
new AetheriaRuntimeBehaviorField ( 3 , PerformanceStat ( 1.5 ) ) ,
new AetheriaRuntimeBehaviorField ( 4 , PerformanceStat ( 2 ) ) ,
2026-07-11 20:23:42 +01:00
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 145 ) ) ,
2026-07-11 20:45:01 +01:00
new AetheriaRuntimeBehaviorField ( 9 , PerformanceStat ( 5 ) ) ,
2026-07-11 20:23:42 +01:00
new AetheriaRuntimeBehaviorField ( 10 , PerformanceStat ( 3 ) ) ,
2026-07-11 20:45:01 +01:00
new AetheriaRuntimeBehaviorField ( 12 , new AetheriaRuntimeBehaviorValue (
"item-key" , "" , 0 , false , "" , "test-ammo" ,
Array . Empty < AetheriaRuntimeBehaviorValue > ( ) , Array . Empty < AetheriaRuntimeBehaviorMapEntry > ( ) ) ) ,
2026-07-11 20:50:09 +01:00
new AetheriaRuntimeBehaviorField ( 13 , Number ( 3 ) ) ,
2026-07-11 20:45:01 +01:00
new AetheriaRuntimeBehaviorField ( 14 , Number ( 0.3 ) ) ,
2026-07-11 20:23:42 +01:00
new AetheriaRuntimeBehaviorField ( 16 , PerformanceStat ( 330 ) ) ,
2026-07-11 20:47:58 +01:00
new AetheriaRuntimeBehaviorField ( 17 , PerformanceStat ( 3 ) ) ,
new AetheriaRuntimeBehaviorField ( 18 , PerformanceStat ( 0.3 ) ) ,
2026-07-11 20:23:42 +01:00
new AetheriaRuntimeBehaviorField ( 19 , PerformanceStat ( 0.2 ) ) ,
new AetheriaRuntimeBehaviorField ( 21 , PerformanceStat ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 22 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 23 , PerformanceStat ( 45 ) ) ,
new AetheriaRuntimeBehaviorField ( 24 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 25 , PerformanceStat ( 1 ) )
] ) ;
2026-07-16 15:47:38 +01:00
var catalog = EquipThrusterBank (
[agent] ,
CatalogItem ( "test-lock-cannon" , weaponPayload ) ,
2026-07-17 02:28:38 +01:00
CatalogItem ( "test-attack-capacitor" , CapacitorPayload ( 50 , 1 ) ) ,
CatalogItem ( "test-attack-sensor" , SensorPayload ( ) ) ) ;
2026-07-11 18:09:43 +01:00
var target = Entity ( 1 , 105 , "raider" ) ;
target . Kind = "station" ;
2026-07-17 02:28:38 +01:00
target . Visibility = 10 ;
2026-07-11 20:50:09 +01:00
target . StatGrids = [ Grid ( "hull" , 14 ) , Grid ( "shield" , 0 ) , Grid ( "heat" , 0 ) ] ;
2026-07-11 18:09:43 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-attack-smoke" ,
CurrentZoneIndex = 0 ,
2026-07-11 19:54:39 +01:00
CurrentEntityKey = "" ,
2026-07-11 18:09:43 +01:00
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ agent , target ] } ]
} ;
var issue = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . IssueAgentTask ,
"commander-smoke" ,
"starbridge-smoke" ,
0 ,
"" ) ;
issue . CommandId = "issue-attack" ;
issue . AgentTask = new AetheriaRuntimeAgentTaskCommand
{
TaskId = "attack-raider" ,
CorporationKey = "player" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Attack ,
Priority = 100 ,
ZoneIndex = 0 ,
TargetEntityIndex = 1 ,
CompletionRadius = 25 ,
WeaponGroup = 0
} ;
var sawTargetCommand = false ;
var sawFireCommand = false ;
2026-07-11 20:16:39 +01:00
var sawPartialLock = false ;
2026-07-15 03:52:56 +01:00
var lockTrace = new List < double > ( ) ;
var attackTrace = new List < string > ( ) ;
2026-07-11 20:16:39 +01:00
var firstLaunchFrame = - 1 ;
2026-07-16 15:47:38 +01:00
var physics = NewPhysics ( ) ;
2026-07-11 18:09:43 +01:00
for ( var frame = 0 ; frame < 60 ; frame + + )
{
var tick = AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-agent-attack-smoke.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
2026-07-16 15:47:38 +01:00
WorldPhysics = physics ,
2026-07-11 18:09:43 +01:00
FrameId = frame ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = frame * 0.1 ,
ObservedCommands = frame = = 0 ? [ issue ] : Array . Empty < AetheriaRuntimeDaemonCommandDocument > ( ) ,
2026-07-11 20:23:42 +01:00
Catalog = catalog ,
2026-07-11 18:09:43 +01:00
BuildPublications = false
} ) ;
sawTargetCommand | = tick . OperationResult . AppliedCommandIds . Any ( id = > id . EndsWith ( ":target" , StringComparison . Ordinal ) ) ;
2026-07-16 22:55:05 +01:00
sawFireCommand | = tick . OperationResult . AppliedCommandIds . Any ( id = > id . Contains ( ":fire-" , StringComparison . Ordinal ) ) ;
2026-07-11 20:23:42 +01:00
var weapon = ( agent . WeaponStates ? ? Array . Empty < AetheriaRuntimeWeaponStateCommit > ( ) )
. Single ( value = > value . OwnerKind = = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ) ;
2026-07-15 03:52:56 +01:00
lockTrace . Add ( weapon . LockProgress ) ;
attackTrace . Add ( $"{frame}:{agent.TargetEntityIndex}:{agent.PositionX:0.##},{agent.PositionZ:0.##}:{agent.DirectionX:0.##},{agent.DirectionY:0.##}:{weapon.LockTargetEntityIndex}" ) ;
2026-07-11 20:16:39 +01:00
sawPartialLock | = weapon . LockProgress > 0 & & weapon . LockProgress < 0.99 ;
2026-07-12 00:54:16 +01:00
if ( firstLaunchFrame < 0 & & run . GameEvents . Any ( value = > value . Kind = = "shot.committed" ) )
2026-07-11 20:16:39 +01:00
firstLaunchFrame = frame ;
2026-07-11 18:09:43 +01:00
if ( string . Equals ( run . AgentTasks . Single ( ) . Status , AetheriaRuntimeAgentTaskStatuses . Completed , StringComparison . Ordinal ) )
break ;
}
Require ( sawTargetCommand , "attack agent must target through the shared target command" ) ;
Require ( sawFireCommand , "attack agent must fire through the shared weapon-group command" ) ;
2026-07-15 03:52:56 +01:00
Require ( sawPartialLock ,
$"attack agent must acquire a persisted partial weapon lock before firing; locks={string.Join(',', lockTrace.Select(value => value.ToString(" 0. # # # ", CultureInfo.InvariantCulture)))} states={string.Join('|', attackTrace)}" ) ;
2026-07-11 20:16:39 +01:00
Require ( firstLaunchFrame > 1 , "accepted fire intent must not bypass progressive weapon lock acquisition" ) ;
2026-07-12 00:54:16 +01:00
Require ( run . GameEvents . Any ( value = > value . Kind = = "shot.committed" & & value . SourceEntityIndex = = agent . EntityIndex ) ,
"accepted fire control must emit authoritative shot commitment chronology" ) ;
Require ( run . GameEvents . Any ( value = > value . Kind = = "shot.committed" & &
2026-07-11 20:47:58 +01:00
value . ItemKey = = "test-lock-cannon" & & Math . Abs ( value . ScalarValue - ( 7.0 / 3.0 ) ) < 0.000001 ) ,
"daemon combat must divide authored damage across the configured burst rounds" ) ;
2026-07-11 20:23:42 +01:00
Require ( ( agent . WeaponStates ? ? Array . Empty < AetheriaRuntimeWeaponStateCommit > ( ) ) . Any ( value = > value . OwnerKind = = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind & &
value . OwnerIndex = = 0 & & value . BehaviorKind = = "LockWeapon" ) ,
"weapon progress must belong to the equipped authored behavior instead of a synthetic entity weapon" ) ;
2026-07-11 20:45:01 +01:00
var authoredWeapon = agent . WeaponStates . Single ( value = >
value . OwnerKind = = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ) ;
2026-07-11 20:50:09 +01:00
RequireEqual ( 0 , authoredWeapon . Ammo ,
"two three-round authored bursts must consume both complete magazines" ) ;
RequireNear ( 40 , agent . BehaviorStates . Single ( value = > value . BehaviorKind = = "Capacitor" ) . CapacitorCharge ,
0.000001 , "two authored bursts must drain exactly their combined energy from canonical capacitor state" ) ;
RequireEqual ( 1 , CargoQuantity ( agent , "test-ammo" ) ,
"one empty magazine must consume exactly one reserve cargo commodity before reload" ) ;
2026-07-12 00:54:16 +01:00
Require ( run . GameEvents . Count ( value = > value . Kind = = "shot.committed" & & value . ItemKey = = "test-lock-cannon" ) > = 6 ,
"two authored bursts must commit all six due rounds through the shot resolver" ) ;
2026-07-12 00:49:00 +01:00
Require ( run . ShotReceipts . Count ( value = > value . WeaponItemKey = = "test-lock-cannon" ) > = 6 & &
2026-07-12 02:38:06 +01:00
run . ShotReceipts . All ( value = > value . Hit & & value . HullAppliedDamage > = 0 & &
2026-07-12 05:13:03 +01:00
value . HullAppliedDamage < = value . NominalDamage & & value . ShieldAbsorbedDamage = = 0 & &
value . DamageType = = "Corrosive" & & Math . Abs ( value . Penetration - 1.5 ) < 0.000001 & &
Math . Abs ( value . DamageSpread - 2 ) < 0.000001 ) ,
"authored rounds must retain damage type, penetration, spread, and exact damage receipts before presentation travel" ) ;
2026-07-12 00:49:00 +01:00
Require ( run . ShotReceipts . Select ( value = > value . ShotId ) . Distinct ( StringComparer . Ordinal ) . Count ( ) = =
run . ShotReceipts . Count ,
"every burst round must own a stable independent shot identity" ) ;
2026-07-11 20:50:09 +01:00
Require ( run . GameEvents . Count ( value = > value . Kind = = "weapon.reload.started" ) = = 1 & &
run . GameEvents . Count ( value = > value . Kind = = "weapon.reload.completed" ) = = 1 ,
"empty magazine transition must publish one authoritative reload start and completion pair" ) ;
var reloadStarted = run . GameEvents . Single ( value = > value . Kind = = "weapon.reload.started" ) . FrameId ;
var reloadCompleted = run . GameEvents . Single ( value = > value . Kind = = "weapon.reload.completed" ) . FrameId ;
Require ( reloadCompleted > reloadStarted & & ! run . GameEvents . Any ( value = >
2026-07-12 00:54:16 +01:00
value . Kind = = "shot.committed" & & value . FrameId > reloadStarted & & value . FrameId < reloadCompleted ) ,
"reload interval must be a shot-free authoritative timeline, not a cosmetic client delay" ) ;
2026-07-11 18:09:43 +01:00
Require ( ! target . IsActive ,
2026-07-12 00:49:00 +01:00
$"attack task must end through daemon shot resolution before presentation projectile contacts; hull={Stat(target, " hull "):0.###} " +
2026-07-11 18:09:43 +01:00
$"agent={agent.PositionX:0.###},{agent.PositionZ:0.###} target={target.PositionX:0.###},{target.PositionZ:0.###} " +
2026-07-12 01:05:25 +01:00
$"projectiles={run.Zones[0].PhysicalPayloads.Count} task={run.AgentTasks.Single().Status}" ) ;
2026-07-11 18:09:43 +01:00
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Completed , run . AgentTasks . Single ( ) . Status ,
"attack task must complete when its target dies" ) ;
2026-07-12 00:49:00 +01:00
var shotSurface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 60 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
Require ( Flatten ( shotSurface . Surface . Root ) . Any ( node = > node . Kind = = "shot.receipt" & &
2026-07-12 01:19:46 +01:00
node . Props [ "itemKey" ] = = "test-lock-cannon" & & node . Props [ "outcome" ] = = "hit" & &
node . Props [ "presentationKind" ] = = "bolt" & &
node . Props . ContainsKey ( "presentationIntensity" ) & &
node . Props . ContainsKey ( "impactKind" ) ) ,
2026-07-12 00:49:00 +01:00
"Eve must project inspectable deterministic shot receipts without reconstructing combat" ) ;
2026-07-11 18:05:19 +01:00
}
2026-07-11 20:19:04 +01:00
private static void AttackTaskAdmissionRejectsImpossibleWork ( )
{
var agent = Entity ( 0 , 0 , "player" ) ;
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Attack ] ;
agent . WeaponGroups = [ new [ ] { 0 } ] ;
var hostile = Entity ( 1 , 100 , "raider" ) ;
var friendly = Entity ( 2 , 100 , "player" ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "attack-admission-smoke" ,
CurrentEntityKey = "" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ agent , hostile , friendly ] } ]
} ;
AetheriaRuntimeDaemonCommandDocument Command ( string id , int targetIndex , int weaponGroup )
{
var command = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . IssueAgentTask , "commander-smoke" , "starbridge-smoke" , 0 , "" ) ;
command . CommandId = id ;
command . AgentTask = new AetheriaRuntimeAgentTaskCommand
{
TaskId = id ,
CorporationKey = "player" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Attack ,
ZoneIndex = 0 ,
TargetEntityIndex = targetIndex ,
WeaponGroup = weaponGroup
} ;
return command ;
}
var result = AetheriaRuntimeDaemonOperations . Execute ( run ,
[
Command ( "missing-target" , 99 , 0 ) ,
Command ( "friendly-target" , 2 , 0 ) ,
Command ( "missing-group" , 1 , 1 ) ,
Command ( "valid-attack" , 1 , 0 )
] ) ;
Require ( result . RejectedCommandIds . SequenceEqual ( new [ ] { "missing-target" , "friendly-target" , "missing-group" } ) ,
"attack admission must reject missing/friendly targets and unavailable weapon groups" ) ;
Require ( result . AppliedCommandIds . SequenceEqual ( new [ ] { "valid-attack" } ) ,
"attack admission must accept executable hostile work" ) ;
Require ( run . AgentTasks . Count = = 1 & & run . AgentTasks [ 0 ] . TaskId = = "valid-attack" ,
"rejected attack orders must not enter the durable corporation queue" ) ;
}
2026-07-11 19:37:57 +01:00
private static void AttackAgentControlsOptimumRangeThroughMovementLever ( )
{
2026-07-16 22:55:05 +01:00
var closing = AttackPlanAtDistance ( 250 , facingTarget : false ) ;
var closingMove = closing . Commands . Single ( command = > command . Kind = = AetheriaRuntimeDaemonCommandKinds . SetMoveVector ) ;
Require ( closingMove . DirectionX > 0.5 & & closingMove . DirectionY < - 0.5 & & closingMove . ScalarValue > 0.99 ,
"loadout-derived long-range attack must blend closing motion with the fossil target-relative strafe" ) ;
var retreating = AttackPlanAtDistance ( 50 , facingTarget : false ) ;
var retreatingMove = retreating . Commands . Single ( command = > command . Kind = = AetheriaRuntimeDaemonCommandKinds . SetMoveVector ) ;
Require ( retreatingMove . DirectionX < - 0.5 & & retreatingMove . DirectionY < - 0.5 ,
"loadout-derived short-range attack must blend opening motion with the fossil target-relative strafe" ) ;
var broadside = AttackPlanAtDistance ( 150 , facingTarget : false ) ;
Require ( ! broadside . Commands . Any ( command = > command . Kind = = AetheriaRuntimeDaemonCommandKinds . FireWeaponGroup ) ,
"an attack agent must not fire a selected group through a hardpoint facing away from its aim" ) ;
var firing = AttackPlanAtDistance ( 150 , facingTarget : true , targetVelocityZ : 8 ) ;
RequireEqual ( 1 , firing . Task . WeaponGroup ,
"agent combat must select the highest current range-DPS group from operational equipment" ) ;
var fire = firing . Commands . Single ( command = > command . Kind = = AetheriaRuntimeDaemonCommandKinds . FireWeaponGroup ) ;
RequireEqual ( 1 , fire . WeaponGroup ,
"the daemon must fire the derived group instead of the task's stale authored group" ) ;
var look = firing . Commands . Single ( command = > command . Kind = = AetheriaRuntimeDaemonCommandKinds . SetLookDirection ) ;
Require ( look . DirectionX > 0.9 & & look . PositionZ > 0.05 ,
"projectile agent aim must lead target velocity through CultMath first-order intercept semantics" ) ;
2026-07-11 19:37:57 +01:00
}
2026-07-16 22:55:05 +01:00
private static ( IReadOnlyList < AetheriaRuntimeDaemonCommandDocument > Commands , AetheriaRuntimeAgentTaskCommit Task )
AttackPlanAtDistance ( double distance , bool facingTarget , double targetVelocityZ = 0 )
2026-07-11 19:37:57 +01:00
{
var agent = Entity ( 0 , 0 , "workers" ) ;
2026-07-16 22:55:05 +01:00
agent . DirectionX = facingTarget ? 1 : 0 ;
agent . DirectionY = facingTarget ? 0 : 1 ;
2026-07-11 19:37:57 +01:00
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Attack ] ;
2026-07-16 22:55:05 +01:00
agent . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Rotation = "None" ,
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "agent-short-weapon" , Quality = 1 , Durability = 1 , Enabled = true }
} ,
new AetheriaRuntimeLoadoutItemSlotCommit
{
Rotation = "None" ,
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "agent-long-weapon" , Quality = 1 , Durability = 1 , Enabled = true }
}
] ;
agent . WeaponGroups = [ new [ ] { 0 } , new [ ] { 1 } ] ;
2026-07-11 19:37:57 +01:00
var target = Entity ( 1 , distance , "raiders" ) ;
2026-07-16 22:55:05 +01:00
target . DirectionY = 1 ;
target . VelocityY = targetVelocityZ ;
2026-07-11 19:37:57 +01:00
var task = new AetheriaRuntimeAgentTaskCommit
{
TaskId = "range-control" ,
CorporationKey = "workers" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Attack ,
ZoneIndex = 0 ,
TargetEntityIndex = 1 ,
WeaponGroup = 0
} ;
2026-07-16 22:55:05 +01:00
AetheriaRuntimeBehaviorPayload Weapon ( double damage , double minimumRange , double range , double velocity ) = >
new ( 0 , AetheriaRuntimeBehaviorKinds . InstantWeapon , 0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( damage ) ) ,
new AetheriaRuntimeBehaviorField ( 5 , PerformanceStat ( minimumRange ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( range ) ) ,
new AetheriaRuntimeBehaviorField ( 16 , PerformanceStat ( velocity ) ) ,
new AetheriaRuntimeBehaviorField ( 17 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 19 , PerformanceStat ( 1 ) )
] ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot (
[
CatalogItem ( "agent-short-weapon" , Weapon ( 10 , 5 , 100 , 80 ) ) ,
CatalogItem ( "agent-long-weapon" , Weapon ( 40 , 25 , 200 , 100 ) )
] , [ ] , [ ] ) ;
2026-07-11 19:37:57 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
{
2026-07-16 22:55:05 +01:00
GenerationSeed = 123 ,
2026-07-11 19:37:57 +01:00
RunId = "agent-range-control-smoke" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ agent , target ] } ] ,
AgentTasks = [ task ]
} ;
2026-07-16 22:55:05 +01:00
return ( AetheriaRuntimeAgentScheduler . AssignAndPlan ( run , 1 , catalog ) , task ) ;
2026-07-11 19:37:57 +01:00
}
2026-07-11 18:05:19 +01:00
private static void SchedulerAssignsHighestPriorityCompatibleTask ( )
{
var agent = Entity ( 0 , 0 , "workers" ) ;
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Explore ] ;
var low = AgentTask ( "low" , 1 ) ;
var high = AgentTask ( "high" , 99 ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-priority-smoke" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ agent ] } ] ,
AgentTasks = [ low , high ]
} ;
AetheriaRuntimeAgentScheduler . AssignAndPlan ( run , 4 ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Assigned , high . Status ,
"highest priority compatible task must claim the available agent" ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Queued , low . Status ,
"lower priority task must remain queued when no controller remains" ) ;
RequireEqual ( "high" , agent . AssignedAgentTaskId , "agent assignment must point at the selected task" ) ;
}
2026-07-11 19:40:36 +01:00
private static void SchedulerRequeuesTaskFromDeadAgent ( )
{
var dead = Entity ( 0 , 0 , "workers" ) ;
dead . IsActive = false ;
dead . AssignedAgentTaskId = "recover-work" ;
var replacement = Entity ( 1 , 0 , "workers" ) ;
replacement . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Explore ] ;
var task = new AetheriaRuntimeAgentTaskCommit
{
TaskId = "recover-work" ,
CorporationKey = "workers" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Explore ,
ZoneIndex = 0 ,
Status = AetheriaRuntimeAgentTaskStatuses . Assigned ,
AssignedEntityIndex = 0 ,
TargetPositionX = 100 ,
DeliveredQuantity = 3 ,
RequestedQuantity = 5
} ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-recovery-smoke" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ dead , replacement ] } ] ,
AgentTasks = [ task ]
} ;
AetheriaRuntimeAgentScheduler . AssignAndPlan ( run , 8 ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Assigned , task . Status ,
"work abandoned by an inactive agent must return to the corporation queue and be reassigned" ) ;
RequireEqual ( replacement . EntityIndex , task . AssignedEntityIndex ,
"compatible active replacement must receive abandoned work" ) ;
RequireEqual ( 3 , task . DeliveredQuantity ,
"reassignment must preserve authoritative task progress" ) ;
Require ( string . IsNullOrWhiteSpace ( dead . AssignedAgentTaskId ) ,
"inactive agent must not retain reservation authority" ) ;
}
private static void SchedulerCollapsesDuplicateAssignmentMarkers ( )
{
var first = Entity ( 0 , 0 , "workers" ) ;
first . AssignedAgentTaskId = "single-owner" ;
var duplicate = Entity ( 1 , 0 , "workers" ) ;
duplicate . AssignedAgentTaskId = "single-owner" ;
2026-07-17 05:46:01 +01:00
duplicate . HelmForward = 1 ;
duplicate . TargetEntityIndex = 7 ;
2026-07-11 19:40:36 +01:00
var task = AgentTask ( "single-owner" , 1 ) ;
task . Status = AetheriaRuntimeAgentTaskStatuses . Assigned ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-single-owner-smoke" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ first , duplicate ] } ] ,
AgentTasks = [ task ]
} ;
AetheriaRuntimeAgentScheduler . AssignAndPlan ( run , 9 ) ;
RequireEqual ( 1 , run . Zones . SelectMany ( zone = > zone . Entities )
. Count ( entity = > string . Equals ( entity . AssignedAgentTaskId , task . TaskId , StringComparison . Ordinal ) ) ,
"one task must have exactly one active carrier after reconciliation" ) ;
RequireEqual ( first . EntityIndex , task . AssignedEntityIndex ,
"duplicate assignment reconciliation must be deterministic" ) ;
2026-07-17 05:46:01 +01:00
RequireNear ( 0 , duplicate . HelmForward , 0.000001 ,
"duplicate assignment reconciliation must release the losing scheduler controls" ) ;
RequireEqual ( - 1 , duplicate . TargetEntityIndex ,
"duplicate assignment reconciliation must release the losing scheduler target" ) ;
}
private static void CancellingAgentTaskReleasesSchedulerControls ( )
{
var agent = Entity ( 0 , 0 , "workers" ) ;
agent . AssignedAgentTaskId = "tow-station" ;
agent . HelmStrafe = 0.75 ;
agent . HelmForward = 1 ;
agent . TargetEntityIndex = 2 ;
agent . ChildEntityIndices = [ 2 ] ;
var station = Entity ( 2 , 0 , "workers" ) ;
station . Kind = "station" ;
var task = new AetheriaRuntimeAgentTaskCommit
{
TaskId = "tow-station" ,
CorporationKey = "workers" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Tow ,
Status = AetheriaRuntimeAgentTaskStatuses . Assigned ,
AssignedEntityIndex = 0 ,
TargetEntityIndex = 2 ,
PendingQuantity = 4 ,
Phase = "delivery"
} ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-cancel-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "" ,
AgentTasks = [ task ] ,
Zones =
[
new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ agent , Entity ( 1 , 0 , "workers" ) , station ]
}
]
} ;
var cancel = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . CancelAgentTask ,
"commander-smoke" ,
"starbridge-smoke" ,
12 ,
"" ) ;
cancel . CommandId = "cancel-tow-station" ;
cancel . AgentTask = new AetheriaRuntimeAgentTaskCommand { TaskId = task . TaskId } ;
var result = AetheriaRuntimeDaemonOperations . Execute (
run ,
[cancel] ,
new AetheriaRuntimeDaemonOperationContext ( ) ) ;
Require ( result . AppliedCommandIds . Contains ( cancel . CommandId , StringComparer . Ordinal ) ,
"task cancellation must commit through the daemon command boundary" ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Cancelled , task . Status ,
"cancelled task must become terminal immediately" ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Cancelled , task . Phase ,
"cancelled task must not retain a counterfeit in-progress phase" ) ;
RequireEqual ( - 1 , task . AssignedEntityIndex ,
"cancelled task must release its assigned agent identity" ) ;
RequireEqual ( 0 , task . PendingQuantity ,
"cancelled transfer work must not retain pending quantity" ) ;
RequireEqual ( "" , agent . AssignedAgentTaskId ,
"cancelled agent must release the durable assignment marker" ) ;
RequireNear ( 0 , agent . HelmStrafe , 0.000001 ,
"cancelled agent must release scheduler-owned strafe input" ) ;
RequireNear ( 0 , agent . HelmForward , 0.000001 ,
"cancelled agent must release scheduler-owned forward input" ) ;
RequireEqual ( - 1 , agent . TargetEntityIndex ,
"cancelled agent must release scheduler-owned targeting" ) ;
Require ( ! agent . ChildEntityIndices . Contains ( station . EntityIndex ) ,
"cancelling an active tow must release the station at its authoritative world position" ) ;
RequireEqual ( 0 , AetheriaRuntimeAgentScheduler . AssignAndPlan ( run , 13 ) . Count ,
"cancelled work must not produce another scheduler command on the next frame" ) ;
2026-07-11 19:40:36 +01:00
}
2026-07-11 18:05:19 +01:00
private static AetheriaRuntimeAgentTaskCommit AgentTask ( string id , int priority ) = > new ( )
{
TaskId = id ,
CorporationKey = "workers" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Explore ,
Priority = priority ,
ZoneIndex = 0 ,
TargetPositionX = 100 ,
CompletionRadius = 5
} ;
2026-07-11 19:34:55 +01:00
private static void SchedulerAssignsShortestGalaxyRoute ( )
{
var distant = Entity ( 0 , 0 , "workers" ) ;
2026-07-15 03:52:56 +01:00
distant . EntityId = "worker.route.distant" ;
2026-07-11 19:34:55 +01:00
distant . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Explore ] ;
var nearby = Entity ( 0 , 0 , "workers" ) ;
2026-07-15 03:52:56 +01:00
nearby . EntityId = "worker.route.nearby" ;
2026-07-11 19:34:55 +01:00
nearby . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Explore ] ;
var task = AgentTask ( "route-choice" , 10 ) ;
task . ZoneIndex = 2 ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-route-choice-smoke" ,
Zones =
[
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , PositionX = 0 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 1 ] , Entities = [ distant ] } ,
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 1 , PositionX = 100 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 0 , 2 ] , Entities = Array . Empty < AetheriaRuntimeEntitySnapshotCommit > ( ) } ,
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 2 , PositionX = 200 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 1 , 3 ] , Entities = Array . Empty < AetheriaRuntimeEntitySnapshotCommit > ( ) } ,
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 3 , PositionX = 300 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 2 ] , Entities = [ nearby ] }
] ,
AgentTasks = [ task ]
} ;
AetheriaRuntimeAgentScheduler . AssignAndPlan ( run , 1 ) ;
RequireEqual ( "route-choice" , nearby . AssignedAgentTaskId ,
"scheduler must reserve the controller with the shortest galaxy route to the task zone" ) ;
Require ( string . IsNullOrWhiteSpace ( distant . AssignedAgentTaskId ) ,
"longer-route controller must remain available" ) ;
}
private static void AgentTraversesGalaxyRouteBeforeExecutingTask ( )
{
2026-07-17 06:25:35 +01:00
var root = Path . Combine ( Path . GetTempPath ( ) , "aetheria-agent-route-restart-" + Guid . NewGuid ( ) . ToString ( "N" ) ) ;
Directory . CreateDirectory ( root ) ;
var statePath = Path . Combine ( root , "world.cc" ) ;
try
2026-07-11 19:34:55 +01:00
{
2026-07-17 06:25:35 +01:00
var agent = Entity ( 0 , 0 , "workers" ) ;
agent . EntityId = "worker.cross-zone.stable" ;
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Explore ] ;
var catalog = EquipThrusterBank ( [ agent ] ) ;
var task = AgentTask ( "cross-zone" , 10 ) ;
task . ZoneIndex = 2 ;
task . TargetPositionX = 0 ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-route-travel-smoke" ,
Zones =
[
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , PositionX = 0 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 1 ] , Entities = [ agent ] } ,
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 1 , PositionX = 100 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 0 , 2 ] , Entities = Array . Empty < AetheriaRuntimeEntitySnapshotCommit > ( ) } ,
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 2 , PositionX = 200 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 1 ] , Entities = Array . Empty < AetheriaRuntimeEntitySnapshotCommit > ( ) }
] ,
AgentTasks = [ task ]
} ;
var appliedTravelCommands = 0 ;
var appliedApproachCommands = 0 ;
var restarted = false ;
var physics = NewPhysics ( ) ;
for ( var frameId = 0 ; frameId < 400 ; frameId + + )
{
var tick = AetheriaRuntimeDaemonTickRunner . Tick (
statePath ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = physics ,
Catalog = catalog ,
FrameId = frameId ,
FixedDeltaSeconds = 0.25 ,
SimulationTimeSeconds = frameId * 0.25 ,
BuildPublications = false
} ) ;
appliedTravelCommands + = tick . OperationResult . AppliedCommandIds . Count ( id = > id . EndsWith ( ":travel" , StringComparison . Ordinal ) ) ;
appliedApproachCommands + = tick . OperationResult . AppliedCommandIds . Count ( id = > id . EndsWith ( ":travel-approach" , StringComparison . Ordinal ) ) ;
agent = run . Zones . SelectMany ( zone = > zone . Entities )
. Single ( entity = > entity . EntityId = = "worker.cross-zone.stable" ) ;
if ( ! restarted & & string . Equals ( agent . WormholeTransition ? . Phase , "entering" , StringComparison . Ordinal ) )
2026-07-11 19:34:55 +01:00
{
2026-07-17 06:25:35 +01:00
var eventCountsBefore = (
Started : run . GameEvents . Count ( value = > value . Kind = = "wormhole.enter.started" ) ,
Transferred : run . GameEvents . Count ( value = > value . Kind = = "wormhole.transferred" ) ,
Completed : run . GameEvents . Count ( value = > value . Kind = = "wormhole.exit.completed" ) ) ;
var durableFrame = new AetheriaRuntimeDaemonFrameDocument
{
FrameId = frameId ,
FixedDeltaSeconds = 0.25 ,
SimulationTimeSeconds = frameId * 0.25 ,
Run = run
} ;
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > (
AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReplaceAsync ( durableFrame ) . GetAwaiter ( ) . GetResult ( ) ;
node . FlushAsync ( soft : false ) . GetAwaiter ( ) . GetResult ( ) ;
}
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
durableFrame = node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > (
AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReadAsync ( ) . GetAwaiter ( ) . GetResult ( )
? ? throw new InvalidOperationException ( "Durable cross-zone agent frame is missing." ) ;
}
run = durableFrame . Run ;
task = run . AgentTasks . Single ( ) ;
agent = run . Zones . SelectMany ( zone = > zone . Entities )
. Single ( entity = > entity . EntityId = = "worker.cross-zone.stable" ) ;
physics . Dispose ( ) ;
physics = NewPhysics ( ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Assigned , task . Status ,
"cross-zone restart must preserve the assigned task during wormhole entry" ) ;
RequireEqual ( task . TaskId , agent . AssignedAgentTaskId ,
"cross-zone restart must preserve the task carrier edge" ) ;
RequireEqual ( "entering" , agent . WormholeTransition ? . Phase ? ? "" ,
"cross-zone restart must preserve the exact wormhole phase" ) ;
Require ( eventCountsBefore = = (
run . GameEvents . Count ( value = > value . Kind = = "wormhole.enter.started" ) ,
run . GameEvents . Count ( value = > value . Kind = = "wormhole.transferred" ) ,
run . GameEvents . Count ( value = > value . Kind = = "wormhole.exit.completed" ) ) ,
"CultCache reopen must not replay wormhole chronology before the next daemon tick" ) ;
restarted = true ;
}
if ( string . Equals ( task . Status , AetheriaRuntimeAgentTaskStatuses . Completed , StringComparison . Ordinal ) )
break ;
}
2026-07-11 19:34:55 +01:00
2026-07-17 06:25:35 +01:00
Require ( restarted ,
"cross-zone task proof must hard-restart while the worker is inside the wormhole timeline" ) ;
Require ( appliedApproachCommands > 0 ,
"agent must approach wormholes through shared movement commands and Ymir before transition" ) ;
RequireEqual ( 2 , appliedTravelCommands ,
"agent must traverse each galaxy edge through the shared wormhole command boundary" ) ;
RequireEqual ( 2 , run . GameEvents . Count ( value = > value . Kind = = "wormhole.enter.started" ) ,
"two route edges must publish exactly two retained entry events across restart" ) ;
RequireEqual ( 2 , run . GameEvents . Count ( value = > value . Kind = = "wormhole.transferred" ) ,
"two route edges must publish exactly two retained transfer events across restart" ) ;
RequireEqual ( 2 , run . GameEvents . Count ( value = > value . Kind = = "wormhole.exit.completed" ) ,
"two route edges must publish exactly two retained completion events across restart" ) ;
RequireEqual ( 1 , run . Zones . Sum ( zone = > zone . Entities . Count ) ,
"cross-zone restart must not clone the durable worker into another zone" ) ;
Require ( run . Zones . Single ( zone = > zone . ZoneIndex = = 2 ) . Entities . Count = = 1 ,
"assigned agent must arrive in the task zone without a parallel teleport owner" ) ;
RequireEqual ( "worker.cross-zone.stable" , run . Zones . Single ( zone = > zone . ZoneIndex = = 2 ) . Entities . Single ( ) . EntityId ,
"zone transfer must preserve stable entity identity while projection indices change" ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Completed , task . Status ,
"agent must execute the task only after arriving in its destination zone" ) ;
}
finally
{
if ( Directory . Exists ( root ) )
Directory . Delete ( root , recursive : true ) ;
}
2026-07-11 19:34:55 +01:00
}
2026-07-16 23:30:19 +01:00
private static void WormholeTraversalUsesPersistedEnterTransferExitPhases ( )
{
var ship = Entity ( 0 , 75 , "player" ) ;
ship . EntityId = "wormhole-traveler" ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "wormhole-transition-smoke" ,
GenerationSeed = 77 ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
DiscoveredZoneIndices = [ 0 ] ,
Zones =
[
new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 , PositionX = 0 , GravityTerrainRadius = 100 ,
AdjacentZoneIndices = [ 1 ] , Entities = [ ship ]
} ,
new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 1 , PositionX = 100 , GravityTerrainRadius = 100 ,
AdjacentZoneIndices = [ 0 , 2 ] , Entities = Array . Empty < AetheriaRuntimeEntitySnapshotCommit > ( )
} ,
new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 2 , PositionX = 200 , GravityTerrainRadius = 100 ,
AdjacentZoneIndices = [ 1 ] , Entities = Array . Empty < AetheriaRuntimeEntitySnapshotCommit > ( )
}
]
} ;
AetheriaRuntimeDaemonCommandDocument Travel ( string id )
{
var command = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . EnterWormhole ,
"pilot" ,
id ,
0 ,
run . CurrentEntityKey ) ;
command . CommandId = id ;
command . TargetZoneIndex = 1 ;
return command ;
}
var physics = NewPhysics ( ) ;
AetheriaRuntimeDaemonTickResult Tick ( int frame , params AetheriaRuntimeDaemonCommandDocument [ ] commands ) = >
AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-wormhole-transition-smoke.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = physics ,
FrameId = frame ,
FixedDeltaSeconds = 1 ,
SimulationTimeSeconds = frame + 1 ,
ObservedCommands = commands ,
BuildPublications = false
} ) ;
var entering = Tick ( 0 , Travel ( "wormhole-start" ) , Travel ( "wormhole-same-batch" ) ) ;
Require ( entering . OperationResult . RejectedCommandIds . Any ( id = > id . Contains ( "wormhole-same-batch" , StringComparison . Ordinal ) ) ,
"one command batch must not admit two competing transition intents for the same entity" ) ;
RequireEqual ( 0 , run . CurrentZoneIndex ,
"wormhole command acceptance must not splice the ship into the destination immediately" ) ;
RequireEqual ( "entering" , ship . WormholeTransition ? . Phase ? ? "" ,
"daemon must persist the entering phase on the authoritative entity" ) ;
Require ( Math . Abs ( ( ship . WormholeTransition ? . Progress ? ? 0 ) - 0.25 ) < 0.0001 ,
"fossil four-second entry timing must advance from fixed daemon time" ) ;
Require ( Math . Abs ( ( ship . WormholeTransition ? . VisualDepthOffset ? ? 0 ) + 250 ) < 0.0001 ,
"transition must expose the fossil depth lever without making the client own motion" ) ;
var enteringView = AetheriaRuntimeGameDocuments . CurrentEntity ( entering . Frame ) . WormholeTransition ;
RequireEqual ( "entering" , enteringView ? . Phase ? ? "" ,
"current-entity projection must expose the same transition state to Eve consumers" ) ;
run = MessagePack . MessagePackSerializer . Deserialize < AetheriaRuntimeRunCheckpointCommit > (
MessagePack . MessagePackSerializer . Serialize ( run ) ) ;
ship = run . Zones . Single ( zone = > zone . ZoneIndex = = 0 ) . Entities . Single ( ) ;
physics . Dispose ( ) ;
physics = NewPhysics ( ) ;
RequireEqual ( "entering" , ship . WormholeTransition ? . Phase ? ? "" ,
"daemon restart must retain the exact mid-entry phase instead of repairing it from client state" ) ;
var duplicate = Tick ( 1 , Travel ( "wormhole-duplicate" ) ) ;
Require ( duplicate . OperationResult . RejectedCommandIds . Any ( id = > id . Contains ( "wormhole-duplicate" , StringComparison . Ordinal ) ) ,
"an entity already inside a wormhole transition must reject a second traversal owner" ) ;
Tick ( 2 ) ;
Tick ( 3 ) ;
RequireEqual ( 1 , run . CurrentZoneIndex ,
"zone ownership must transfer only after the entering phase completes" ) ;
var arrived = run . Zones . Single ( zone = > zone . ZoneIndex = = 1 ) . Entities . Single ( ) ;
RequireEqual ( "exiting" , arrived . WormholeTransition ? . Phase ? ? "" ,
"transferred ship must persist a distinct exiting phase" ) ;
Require ( run . DiscoveredZoneIndices . Contains ( 2 ) ,
"arrival must reveal the destination adjacency using the fossil discovery rule" ) ;
Tick ( 4 ) ;
Tick ( 5 ) ;
Tick ( 6 ) ;
Tick ( 7 ) ;
RequireEqual ( "completed" , arrived . WormholeTransition ? . Phase ? ? "" ,
"the completion frame must preserve a presentation lever before normal physics resumes" ) ;
Require ( Math . Abs ( Math . Sqrt ( arrived . VelocityX * arrived . VelocityX + arrived . VelocityY * arrived . VelocityY ) - 20 ) < 0.0001 ,
"completed exit must restore the fossil twenty-unit launch velocity" ) ;
Require ( Math . Abs ( Math . Sqrt ( Math . Pow ( arrived . PositionX + 75 , 2 ) + Math . Pow ( arrived . PositionZ , 2 ) ) - 50 ) < 0.001 ,
"completed exit must place the ship fifty units from the destination wormhole" ) ;
Tick ( 8 ) ;
Require ( arrived . WormholeTransition = = null ,
"the tick after completion must release input and Ymir instead of leaving a permanent transition flag" ) ;
RequireEqual ( 1 , run . GameEvents . Count ( value = > value . Kind = = "wormhole.enter.started" ) ,
"entry feedback must have stable exactly-once chronology" ) ;
RequireEqual ( 1 , run . GameEvents . Count ( value = > value . Kind = = "wormhole.transferred" ) ,
"transfer feedback must have stable exactly-once chronology" ) ;
RequireEqual ( 1 , run . GameEvents . Count ( value = > value . Kind = = "wormhole.exit.completed" ) ,
"exit feedback must have stable exactly-once chronology" ) ;
}
2026-07-11 19:49:48 +01:00
private static void IdleAgentReturnsToCanonicalHomeAndDocks ( )
{
var worker = Entity ( 0 , 0 , "workers" ) ;
worker . EntityId = "worker.return-home" ;
worker . HomeEntityId = "station.home" ;
worker . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Haul ] ;
var home = Entity ( 0 , 60 , "workers" ) ;
home . EntityId = "station.home" ;
home . Kind = "station" ;
2026-07-17 00:17:12 +01:00
home . DockingBays = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "station-docking-bay" }
} ] ;
home . DockingBayAssignments = [ - 1 ] ;
home . DockingBayContents = [ Cargo ( ) ] ;
2026-07-16 15:47:38 +01:00
var catalog = EquipThrusterBank ( [ worker ] ) ;
2026-07-11 19:49:48 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-return-home-smoke" ,
Zones =
[
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , PositionX = 0 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 1 ] , Entities = [ worker ] } ,
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 1 , PositionX = 100 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 0 , 2 ] , Entities = Array . Empty < AetheriaRuntimeEntitySnapshotCommit > ( ) } ,
new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 2 , PositionX = 200 , GravityTerrainRadius = 100 , AdjacentZoneIndices = [ 1 ] , Entities = [ home ] }
]
} ;
var sawApproach = false ;
var travelCount = 0 ;
var sawDock = false ;
var rejectedHomeCommands = new List < string > ( ) ;
2026-07-17 00:17:12 +01:00
var minimumHomeDistance = double . PositiveInfinity ;
var maximumHomeSpeed = 0.0 ;
2026-07-16 15:47:38 +01:00
var physics = NewPhysics ( ) ;
2026-07-16 23:30:19 +01:00
for ( var frame = 0 ; frame < 500 ; frame + + )
2026-07-11 19:49:48 +01:00
{
var tick = AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-agent-return-home-smoke.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
2026-07-16 15:47:38 +01:00
WorldPhysics = physics ,
Catalog = catalog ,
2026-07-11 19:49:48 +01:00
FrameId = frame ,
2026-07-16 23:30:19 +01:00
FixedDeltaSeconds = 0.25 ,
SimulationTimeSeconds = frame * 0.25 ,
2026-07-11 19:49:48 +01:00
BuildPublications = false
} ) ;
sawApproach | = tick . OperationResult . AppliedCommandIds . Any ( id = > id . Contains ( ":home-approach" , StringComparison . Ordinal ) ) ;
travelCount + = tick . OperationResult . AppliedCommandIds . Count ( id = > id . EndsWith ( ":home-travel" , StringComparison . Ordinal ) ) ;
sawDock | = tick . OperationResult . AppliedCommandIds . Any ( id = > id . EndsWith ( ":home-dock" , StringComparison . Ordinal ) ) ;
rejectedHomeCommands . AddRange ( tick . OperationResult . RejectedCommandIds . Where ( id = > id . Contains ( ":home-" , StringComparison . Ordinal ) ) ) ;
2026-07-17 00:17:12 +01:00
var currentHomeZone = run . Zones . Single ( zone = > zone . ZoneIndex = = 2 ) ;
var currentWorker = currentHomeZone . Entities . FirstOrDefault ( entity = > entity . EntityId = = "worker.return-home" ) ;
var currentHome = currentHomeZone . Entities . FirstOrDefault ( entity = > entity . EntityId = = "station.home" ) ;
if ( currentWorker ! = null & & currentHome ! = null )
{
minimumHomeDistance = Math . Min ( minimumHomeDistance , Math . Sqrt (
Math . Pow ( currentWorker . PositionX - currentHome . PositionX , 2 ) +
Math . Pow ( currentWorker . PositionZ - currentHome . PositionZ , 2 ) ) ) ;
maximumHomeSpeed = Math . Max ( maximumHomeSpeed , Math . Sqrt (
currentWorker . VelocityX * currentWorker . VelocityX +
currentWorker . VelocityY * currentWorker . VelocityY ) ) ;
}
2026-07-11 19:49:48 +01:00
if ( sawDock )
break ;
}
var homeZone = run . Zones . Single ( zone = > zone . ZoneIndex = = 2 ) ;
var arrivedWorker = homeZone . Entities . Single ( entity = > entity . EntityId = = "worker.return-home" ) ;
var arrivedHome = homeZone . Entities . Single ( entity = > entity . EntityId = = "station.home" ) ;
Require ( sawApproach , "idle worker must approach its route and home through shared movement commands" ) ;
RequireEqual ( 2 , travelCount , "idle worker must traverse the shortest route to its canonical home" ) ;
Require ( sawDock ,
2026-07-17 00:17:12 +01:00
$"idle worker must dock through the daemon docking command; worker={arrivedWorker.PositionX:0.###},{arrivedWorker.PositionZ:0.###} home={arrivedHome.PositionX:0.###},{arrivedHome.PositionZ:0.###} minDistance={minimumHomeDistance:0.###} maxSpeed={maximumHomeSpeed:0.###} rejected={string.Join(" , ", rejectedHomeCommands)}" ) ;
2026-07-11 19:49:48 +01:00
Require ( arrivedHome . DockingBayAssignments . Contains ( arrivedWorker . EntityIndex ) ,
"home docking parentage must be the authoritative completion fact" ) ;
var settled = AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-agent-return-home-settled-smoke.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
2026-07-16 23:30:19 +01:00
WorldPhysics = physics , Catalog = catalog , FrameId = 501 ,
FixedDeltaSeconds = 0.25 , SimulationTimeSeconds = 125.25 , BuildPublications = false
2026-07-11 19:49:48 +01:00
} ) ;
Require ( ! settled . OperationResult . AppliedCommandIds . Any ( id = > id . Contains ( ":home-" , StringComparison . Ordinal ) ) ,
"docked worker must not emit a perpetual homecoming repair loop" ) ;
}
2026-07-11 19:54:39 +01:00
private static void ControlledShipDoesNotReceiveAutonomousHelmCommands ( )
{
var controlled = Entity ( 0 , 100 , "workers" ) ;
controlled . EntityId = "controlled-worker" ;
controlled . HomeEntityId = "controlled-home" ;
controlled . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Explore ] ;
var home = Entity ( 1 , 0 , "workers" ) ;
home . EntityId = "controlled-home" ;
home . Kind = "station" ;
var task = AgentTask ( "controlled-task" , 10 ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "controlled-agent-authority-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ controlled , home ] } ] ,
AgentTasks = [ task ]
} ;
var commands = AetheriaRuntimeAgentScheduler . AssignAndPlan ( run , 1 ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Queued , task . Status ,
"manual helm owner must not be conscripted into autonomous corporation work" ) ;
Require ( commands . Count = = 0 ,
"controlled ship must emit no task or return-home commands without delegated helm authority" ) ;
}
2026-07-11 18:05:19 +01:00
private static void AgentClaimsAndCompletesExploreTaskThroughCommands ( )
{
var agent = Entity ( 0 , 0 , "workers" ) ;
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Explore ] ;
2026-07-16 15:47:38 +01:00
var catalog = EquipThrusterBank ( [ agent ] ) ;
2026-07-11 18:05:19 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-task-smoke" ,
CurrentZoneIndex = 0 ,
2026-07-11 19:54:39 +01:00
CurrentEntityKey = "" ,
2026-07-11 18:05:19 +01:00
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ agent ] } ]
} ;
var issue = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . IssueAgentTask ,
"commander-smoke" ,
"starbridge-smoke" ,
0 ,
"" ) ;
issue . CommandId = "issue-explore" ;
issue . AgentTask = new AetheriaRuntimeAgentTaskCommand
{
TaskId = "explore-east" ,
CorporationKey = "workers" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Explore ,
Priority = 50 ,
ZoneIndex = 0 ,
TargetPositionX = 50 ,
TargetPositionZ = 0 ,
CompletionRadius = 5
} ;
var completed = false ;
2026-07-16 15:47:38 +01:00
var physics = NewPhysics ( ) ;
for ( var frame = 0 ; frame < = 60 ; frame + + )
2026-07-11 18:05:19 +01:00
{
var tick = AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-agent-task-smoke.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
2026-07-16 15:47:38 +01:00
WorldPhysics = physics ,
2026-07-11 18:05:19 +01:00
FrameId = frame ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = frame * 0.1 ,
ObservedCommands = frame = = 0 ? [ issue ] : Array . Empty < AetheriaRuntimeDaemonCommandDocument > ( ) ,
2026-07-16 15:47:38 +01:00
Catalog = catalog ,
2026-07-11 18:05:19 +01:00
BuildPublications = false
} ) ;
if ( frame = = 0 )
{
Require ( tick . OperationResult . AppliedCommandIds . Contains ( "issue-explore" ) ,
"commander task command must enter the normal tick reducer" ) ;
Require ( tick . OperationResult . AppliedCommandIds . Any ( id = > id . Contains ( ":explore-east:0:move" , StringComparison . Ordinal ) ) ,
"agent movement must return through the same command receipts" ) ;
}
completed = string . Equals ( run . AgentTasks . Single ( ) . Status , AetheriaRuntimeAgentTaskStatuses . Completed , StringComparison . Ordinal ) ;
if ( completed )
break ;
}
2026-07-16 15:47:38 +01:00
Require ( completed ,
$"agent must complete an explore task without direct position mutation; position={agent.PositionX:0.###},{agent.PositionZ:0.###} velocity={agent.VelocityX:0.###},{agent.VelocityY:0.###}" ) ;
2026-07-11 18:05:19 +01:00
Require ( string . IsNullOrWhiteSpace ( agent . AssignedAgentTaskId ) , "completed task must release the agent" ) ;
Require ( agent . PositionX > = 45 , "agent must reach the task through repeated movement commands" ) ;
var frameDocument = new AetheriaRuntimeDaemonFrameDocument { FrameId = 21 , Run = run } ;
var commander = AetheriaRuntimeDaemonGameSurfaceBuilder . BuildCommander (
frameDocument ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "agent-task-smoke" ) ) ;
var taskNode = Flatten ( commander . Surface . Root )
. Single ( component = > string . Equals ( component . Id , "aetheria.starbridge.commander.tasks.explore_east" , StringComparison . Ordinal ) ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Completed , taskNode . Props [ "status" ] ,
"commander Eve surface must publish authoritative task status" ) ;
Require ( commander . Commands . Any ( command = > string . Equals ( command . Command , "aetheria.daemon.issue_agent_task" , StringComparison . Ordinal ) ) ,
"commander Eve surface must advertise task issue command" ) ;
2026-07-11 19:58:50 +01:00
var roster = Flatten ( commander . Surface . Root )
. Single ( component = > string . Equals ( component . Kind , "agent.roster" , StringComparison . Ordinal ) ) ;
var worker = Flatten ( roster )
. Single ( component = > string . Equals ( component . Kind , "agent.item" , StringComparison . Ordinal ) ) ;
Require ( ! string . IsNullOrWhiteSpace ( worker . Props [ "entityId" ] ) ,
"commander Eve roster must expose stable provider-owned worker identity" ) ;
Require ( worker . Props [ "capabilities" ] . Split ( ',' ) . Contains ( AetheriaRuntimeAgentTaskTypes . Explore ) ,
"commander Eve roster must expose provider-owned capability claims" ) ;
2026-07-11 20:03:41 +01:00
RequireEqual ( "idle" , worker . Props [ "status" ] ,
"commander Eve roster must publish generic status for runtime-independent lowering" ) ;
Require ( worker . Props [ "badges" ] . Split ( ',' ) . Contains ( AetheriaRuntimeAgentTaskTypes . Explore ) ,
"commander Eve roster must publish capability badges through the generic item contract" ) ;
2026-07-11 19:58:50 +01:00
RequireEqual ( "" , worker . Props [ "assignedTaskId" ] ,
"completed worker assignment must be visible as released on the Eve roster" ) ;
RequireEqual ( "false" , worker . Props [ "controlled" ] ,
"commander Eve roster must distinguish autonomous workers from manual helm authority" ) ;
2026-07-11 17:55:50 +01:00
}
2026-07-17 06:21:10 +01:00
private static void AgentTaskSurvivesCultCacheRestart ( )
{
var root = Path . Combine ( Path . GetTempPath ( ) , "aetheria-agent-restart-" + Guid . NewGuid ( ) . ToString ( "N" ) ) ;
Directory . CreateDirectory ( root ) ;
var statePath = Path . Combine ( root , "world.cc" ) ;
try
{
var agent = Entity ( 0 , 0 , "workers" ) ;
agent . AgentTaskCapabilities = [ AetheriaRuntimeAgentTaskTypes . Explore ] ;
var catalog = EquipThrusterBank ( [ agent ] ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "agent-task-restart-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ agent ] } ]
} ;
var issue = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . IssueAgentTask ,
"commander-smoke" ,
run . RunId ,
0 ,
"" ) ;
issue . CommandId = "issue-restart-explore" ;
issue . AgentTask = new AetheriaRuntimeAgentTaskCommand
{
TaskId = "restart-explore-east" ,
CorporationKey = "workers" ,
TaskType = AetheriaRuntimeAgentTaskTypes . Explore ,
Priority = 50 ,
ZoneIndex = 0 ,
TargetPositionX = 80 ,
TargetPositionZ = 0 ,
CompletionRadius = 5
} ;
var physics = NewPhysics ( ) ;
for ( var frameId = 0 ; frameId < = 8 ; frameId + + )
AetheriaRuntimeDaemonTickRunner . Tick (
statePath ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = physics ,
FrameId = frameId ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = frameId * 0.1 ,
ObservedCommands = frameId = = 0
? [ issue ]
: Array . Empty < AetheriaRuntimeDaemonCommandDocument > ( ) ,
Catalog = catalog ,
BuildPublications = false
} ) ;
var taskBeforeRestart = run . AgentTasks . Single ( ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Assigned , taskBeforeRestart . Status ,
"restart fixture must persist an actively assigned task rather than a queued or completed shell" ) ;
RequireEqual ( taskBeforeRestart . TaskId , agent . AssignedAgentTaskId ,
"restart fixture must persist the scheduler's single agent assignment" ) ;
Require ( agent . PositionX > 0 & & agent . PositionX < 75 ,
"restart fixture must stop during commanded Ymir travel" ) ;
var positionBeforeRestart = agent . PositionX ;
var frame = new AetheriaRuntimeDaemonFrameDocument
{
FrameId = 8 ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = 0.8 ,
Run = run
} ;
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > (
AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReplaceAsync ( frame ) . GetAwaiter ( ) . GetResult ( ) ;
node . FlushAsync ( soft : false ) . GetAwaiter ( ) . GetResult ( ) ;
}
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
frame = node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > (
AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReadAsync ( ) . GetAwaiter ( ) . GetResult ( )
? ? throw new InvalidOperationException ( "Durable agent-task frame is missing." ) ;
}
run = frame . Run ;
agent = run . Zones . Single ( ) . Entities . Single ( ) ;
var restoredTask = run . AgentTasks . Single ( ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Assigned , restoredTask . Status ,
"CultCache restart must preserve the active task status" ) ;
RequireEqual ( restoredTask . TaskId , agent . AssignedAgentTaskId ,
"CultCache restart must preserve the task-to-agent ownership edge" ) ;
RequireNear ( positionBeforeRestart , agent . PositionX , 0.000001 ,
"CultCache restart must preserve the last daemon/Ymir committed pose" ) ;
physics = NewPhysics ( ) ;
var completed = false ;
for ( var frameId = 9 ; frameId < = 100 ; frameId + + )
{
AetheriaRuntimeDaemonTickRunner . Tick (
statePath ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = physics ,
FrameId = frameId ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = frameId * 0.1 ,
Catalog = catalog ,
BuildPublications = false
} ) ;
completed = string . Equals (
run . AgentTasks . Single ( ) . Status ,
AetheriaRuntimeAgentTaskStatuses . Completed ,
StringComparison . Ordinal ) ;
if ( completed )
break ;
}
Require ( completed & & agent . PositionX > = 75 ,
"restored task must reconstruct Ymir from committed world truth and finish through scheduler movement commands" ) ;
RequireEqual ( 1 , run . AgentTasks . Count ,
"restart must not duplicate the durable task when the scheduler resumes" ) ;
RequireEqual ( "" , agent . AssignedAgentTaskId ,
"completed restored task must release scheduler control exactly once" ) ;
var commander = AetheriaRuntimeDaemonGameSurfaceBuilder . BuildCommander (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 100 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "agent-task-restart-smoke" ) ) ;
var taskNode = Flatten ( commander . Surface . Root ) . Single ( node = >
node . Id = = "aetheria.starbridge.commander.tasks.restart_explore_east" ) ;
RequireEqual ( AetheriaRuntimeAgentTaskStatuses . Completed , taskNode . Props [ "status" ] ,
"generic Eve commander reconnect must observe the restored task's authoritative completion" ) ;
}
finally
{
if ( Directory . Exists ( root ) )
Directory . Delete ( root , recursive : true ) ;
}
}
2026-07-11 17:55:50 +01:00
private static void MultipleActorsUseTheSameMovementLever ( )
{
var player = Entity ( 0 , 0 , "player" ) ;
2026-07-16 15:47:38 +01:00
var agent = Entity ( 1 , 200 , "worker" ) ;
var catalog = EquipThrusterBank ( [ player , agent ] ) ;
2026-07-15 03:52:56 +01:00
player . TargetEntityIndex = agent . EntityIndex ;
2026-07-11 17:55:50 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "shared-lever-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ player , agent ] } ]
} ;
var commands = new [ ]
{
MovementCommand ( "player-move" , "zone.0.entity.0" , 1 , 0 ) ,
MovementCommand ( "agent-move" , "zone.0.entity.1" , 0 , 1 )
} ;
var operation = AetheriaRuntimeDaemonOperations . Execute ( run , commands ) ;
RequireEqual ( 2 , operation . Intents . Movements . Count , "movement intent must retain one lever position per actor" ) ;
2026-07-16 15:47:38 +01:00
var physics = NewPhysics ( ) ;
for ( var step = 0 ; step < 2 ; step + + )
AetheriaRuntimeDaemonSimulation . Step (
run ,
operation . Intents ,
0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
physics ,
catalog ,
step + 1 ) ;
Require ( player . VelocityX > 0 & & Math . Abs ( player . VelocityY ) < Math . Abs ( player . VelocityX ) * 0.1 ,
$"player command must drive its actor through the shared movement lever; velocity={player.VelocityX:0.###},{player.VelocityY:0.###}" ) ;
Require ( agent . VelocityY > 0 & & Math . Abs ( agent . VelocityX ) < Math . Abs ( agent . VelocityY ) * 0.1 ,
$"agent command must drive its actor through the shared movement lever; velocity={agent.VelocityX:0.###},{agent.VelocityY:0.###}" ) ;
2026-07-15 03:52:56 +01:00
var release = MovementCommand ( "player-release" , "zone.0.entity.0" , 0 , 0 ) ;
release . ScalarValue = 0 ;
var releaseOperation = AetheriaRuntimeDaemonOperations . Execute ( run , [ release ] ) ;
AetheriaRuntimeDaemonSimulation . Step (
run ,
releaseOperation . Intents ,
0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-16 15:47:38 +01:00
physics ,
catalog ,
3 ) ;
2026-07-15 03:52:56 +01:00
RequireEqual ( agent . EntityIndex , player . TargetEntityIndex ,
"releasing the movement lever must not steal targeting authority" ) ;
2026-07-11 17:55:50 +01:00
}
2026-07-16 15:47:38 +01:00
private static void DirectionalThrustersOwnOrdinaryFlightFeedback ( )
{
var ship = Entity ( 0 , 0 , "player" ) ;
var catalog = EquipThrusterBank ( [ ship ] ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "ordinary-thruster-flight-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship ] } ]
} ;
var operation = AetheriaRuntimeDaemonOperations . Execute (
run , [ MovementCommand ( "forward-thrust" , "zone.0.entity.0" , 0 , 1 ) ] ) ;
var physics = NewPhysics ( ) ;
AetheriaRuntimeDaemonSimulation . Step (
run , operation . Intents , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
physics , catalog , 1 ) ;
var thrusterStates = ship . BehaviorStates
. Where ( value = > value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . Thruster )
. ToArray ( ) ;
RequireEqual ( 8 , thrusterStates . Length ,
"ordinary hull fixture must fly through its directional thruster bank" ) ;
Require ( thrusterStates . Count ( value = > value . ThrusterAxis > 0.99 ) = = 2 & &
thrusterStates . Where ( value = > value . ThrusterAxis > 0.99 )
. All ( value = > ship . Equipment [ value . OwnerIndex ] . Rotation = = "Half" ) ,
"forward helm must fire only the reversed forward-thrust pair when no turn is requested" ) ;
Require ( thrusterStates . Where ( value = > value . ThrusterAxis > 0.99 )
. All ( value = > value . ThrusterThrust > 0 & & Math . Abs ( value . ThrusterTorque ) > 0.5 ) ,
"thruster state must expose evaluated thrust and placement-derived torque" ) ;
Require ( ship . VelocityY > 0 & & Math . Abs ( ship . VelocityX ) < Math . Abs ( ship . VelocityY ) * 0.1 ,
"ordinary thrust must become Ymir-integrated forward velocity" ) ;
Require ( ship . Visibility > 1.9 ,
"successful thruster execution must publish its maximum plume visibility" ) ;
Require ( thrusterStates . Where ( value = > value . ThrusterAxis > 0.99 )
. Any ( value = > AetheriaRuntimeThermalSimulation . EquipmentTemperature (
ship , catalog , value . OwnerIndex ) > ship . EquipmentStates
. Single ( state = > state . EquipmentIndex = = value . OwnerIndex ) . Temperature ) ,
"successful thruster execution must deposit authored heat into daemon equipment cells" ) ;
Require ( ! ship . BehaviorStates . Any ( value = > value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . AetherDrive ) ,
"ordinary flight must not manufacture an AetherDrive behavior" ) ;
}
private static void UnpoweredThrustersCannotMoveOrAdvertisePlume ( )
{
var ship = Entity ( 0 , 0 , "player" ) ;
var catalog = EquipThrusterBank ( [ ship ] ) ;
var thruster = catalog . Items . Single ( value = > value . ItemKey = = "smoke-directional-thruster" ) ;
thruster . BehaviorPayloads . Single ( ) . Fields = thruster . BehaviorPayloads . Single ( ) . Fields
. Select ( field = > field . Key = = 4
? new AetheriaRuntimeBehaviorField ( 4 , PerformanceStat ( 10 ) )
: field )
. ToArray ( ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "unpowered-thruster-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship ] } ]
} ;
var operation = AetheriaRuntimeDaemonOperations . Execute (
run , [ MovementCommand ( "unpowered-forward" , "zone.0.entity.0" , 0 , 1 ) ] ) ;
AetheriaRuntimeDaemonSimulation . Step (
run , operation . Intents , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
NewPhysics ( ) , catalog , 1 ) ;
RequireNear ( 0 , ship . VelocityX , 0.000001 ,
"an unfunded thruster bank must not create lateral velocity" ) ;
RequireNear ( 0 , ship . VelocityY , 0.000001 ,
"an unfunded thruster bank must not create forward velocity" ) ;
RequireNear ( 0 , ship . Visibility , 0.000001 ,
"an unfunded thruster bank must not advertise a plume that did not execute" ) ;
}
2026-07-17 03:25:16 +01:00
private static void SpecializedBehaviorSuccessGatesTrailingWear ( )
{
var ship = Entity ( 0 , 0 , "player" ) ;
var catalog = EquipThrusterBank ( [ ship ] ) ;
var thrusterItem = catalog . Items . Single ( value = > value . ItemKey = = "smoke-directional-thruster" ) ;
thrusterItem . BehaviorPayloads =
[
ThrusterPayload ( ) ,
new AetheriaRuntimeBehaviorPayload ( 1 , "Wear" , 0 ,
[new AetheriaRuntimeBehaviorField(1, BoolValue(true))] )
] ;
AetheriaRuntimeThermalSimulation . EnsureTopology ( ship , catalog ) ;
AetheriaRuntimeThermalSimulation . EnsureState ( ship ) ;
AetheriaRuntimeThermalSimulation . UpdateEquipmentStates ( ship , catalog , 0.1 ) ;
foreach ( var state in ship . EquipmentStates )
state . Wear = 1 ;
AetheriaRuntimeEnergySimulation . BeginTick ( ship , catalog ) ;
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ ship ] , [ ] , catalog , 0.1 ) ;
AetheriaRuntimeFlightSimulation . Step ( [ ship ] , [ ] , catalog , 0.1 , 1 , 1 , 0.001 , 1 ) ;
AetheriaRuntimeBehaviorSimulation . CompleteDeferredChains ( ship , catalog , 0.1 ) ;
Require ( ship . Equipment . All ( slot = > Math . Abs ( slot . Item . Durability - 1 ) < 0.000001 ) ,
"idle thrusters must return false and leave every trailing wear behavior unreachable" ) ;
ship . HelmForward = 1 ;
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ ship ] , [ ] , catalog , 0.1 ) ;
AetheriaRuntimeFlightSimulation . Step ( [ ship ] , [ ] , catalog , 0.1 , 1 , 1 , 0.001 , 1 ) ;
AetheriaRuntimeBehaviorSimulation . CompleteDeferredChains ( ship , catalog , 0.1 ) ;
RequireEqual ( 2 , ship . Equipment . Count ( slot = > slot . Item . Durability < 1 ) ,
"only the two successful forward thrusters may resume into trailing wear" ) ;
Require ( ship . Equipment . Where ( slot = > slot . Item . Durability < 1 )
. All ( slot = > Math . Abs ( slot . Item . Durability - 0.9 ) < 0.000001 ) ,
"each successful specialized behavior must resume its tail exactly once" ) ;
AetheriaRuntimeBehaviorSimulation . CompleteDeferredChains ( ship , catalog , 0.1 ) ;
Require ( ship . Equipment . Where ( slot = > slot . Item . Durability < 1 )
. All ( slot = > Math . Abs ( slot . Item . Durability - 0.9 ) < 0.000001 ) ,
"replaying deferred completion in the same tick must not apply trailing wear twice" ) ;
}
2026-07-16 15:47:38 +01:00
private static void RareAetherDriveSpoolsOnlyOnModifiedHullFixture ( )
{
var ship = Entity ( 0 , 0 , "player" ) ;
var catalog = EquipAetherDrive ( [ ship ] ) ;
var hull = catalog . FindItem ( ship . HullItemKey ) ! ;
var drive = catalog . Items . Single ( value = > value . ItemKey = = "smoke-aether-drive" ) ;
Require ( drive . HardpointType = = "AetherDrive" & &
hull . Hardpoints . Count ( value = > value . Type = = drive . HardpointType ) = = 1 ,
"rare AetherDrive fixture must use an explicit modified-hull hardpoint instead of the ordinary hull path" ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "rare-aether-drive-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship ] } ]
} ;
var operation = AetheriaRuntimeDaemonOperations . Execute (
run , [ MovementCommand ( "rare-drive-forward" , "zone.0.entity.0" , 0 , 1 ) ] ) ;
var physics = NewPhysics ( ) ;
for ( var frame = 1 ; frame < = 2 ; frame + + )
AetheriaRuntimeDaemonSimulation . Step (
run , operation . Intents , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
physics , catalog , frame ) ;
var state = ship . BehaviorStates . Single ( value = >
value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . AetherDrive ) ;
Require ( state . AetherDriveRpmX > 0 & & state . AetherDriveMaximumRpm > 0 ,
"rare installed drive must persist rotor spool state" ) ;
Require ( ship . VelocityY > 0 ,
"rare installed drive must contribute force only after its rotor has spooled" ) ;
Require ( ! ship . BehaviorStates . Any ( value = > value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . Thruster ) ,
"isolated AetherDrive proof must not conceal its force behind ordinary thrusters" ) ;
}
2026-07-15 06:10:08 +01:00
private static void LookDirectionRejectsInvalidVectorsWithoutMutatingTheShip ( )
{
var player = Entity ( 0 , 0 , "player" ) ;
player . DirectionX = 0.6 ;
player . DirectionY = 0.8 ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "invalid-look-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ player ] } ]
} ;
AetheriaRuntimeDaemonCommandDocument Look ( string id , double x , double z )
{
var command = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . SetLookDirection ,
"look-smoke" ,
"look-session" ,
0 ,
"zone.0.entity.0" ) ;
command . CommandId = id ;
command . DirectionX = x ;
command . PositionZ = z ;
return command ;
}
var operation = AetheriaRuntimeDaemonOperations . Execute ( run ,
[
Look ( "zero-look" , 0 , 0 ) ,
Look ( "nan-look" , double . NaN , 1 ) ,
Look ( "infinite-look" , 1 , double . PositiveInfinity )
] ) ;
Require ( operation . RejectedCommandIds . SequenceEqual ( new [ ] { "zero-look" , "nan-look" , "infinite-look" } ) ,
"zero and non-finite look intents must be rejected at the daemon authority boundary" ) ;
RequireNear ( 0.6 , player . DirectionX , 0.000001 ,
"rejected look intents must not mutate the authoritative ship direction X" ) ;
RequireNear ( 0.8 , player . DirectionY , 0.000001 ,
"rejected look intents must not mutate the authoritative ship direction Z" ) ;
}
2026-07-11 17:55:50 +01:00
private static AetheriaRuntimeDaemonCommandDocument MovementCommand (
string commandId ,
string actor ,
double x ,
double y )
{
var command = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . SetMoveVector ,
"shared-control-smoke" ,
"shared-control-session" ,
0 ,
actor ) ;
command . CommandId = commandId ;
command . DirectionX = x ;
command . DirectionY = y ;
command . ScalarValue = 1 ;
return command ;
2026-07-11 17:50:26 +01:00
}
2026-07-12 06:01:14 +01:00
private static void EnergyNetworkSettlesReactorAfterConsumers ( )
{
var entity = Entity ( 0 , 0 , "player" ) ;
entity . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "ledger-capacitor" , Quality = 1 , Durability = 1 , Enabled = true } } ,
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "ledger-reactor" , Quality = 1 , Durability = 1 , Enabled = true } }
] ;
entity . BehaviorStates =
[
new AetheriaRuntimeBehaviorStateCommit
{
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ,
OwnerIndex = 0 , BehaviorIndex = 0 , BehaviorKind = "Capacitor" ,
CapacitorCharge = 2 , CapacitorCapacity = 10 , CapacitorEfficiency = 0.5
} ,
new AetheriaRuntimeBehaviorStateCommit
{
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ,
OwnerIndex = 1 , BehaviorIndex = 0 , BehaviorKind = "Reactor"
}
] ;
entity . StatGrids =
[
Grid ( "hull" , 100 ) , Grid ( "shield" , 0 ) , Grid ( "heat" , 280 ) ,
Grid ( "temperature" , 280 ) , Grid ( "thermal-mass" , 1 ) , Grid ( "conductivity" , 1 )
] ;
var capacitorItem = CatalogItem ( "ledger-capacitor" , CapacitorPayload ( 10 , 0.5 ) ) ;
capacitorItem . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var reactorPayload = new AetheriaRuntimeBehaviorPayload ( 0 , "Reactor" , 100 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 4 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 2 ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , PerformanceStat ( 0.5 ) ) ,
new AetheriaRuntimeBehaviorField ( 4 , PerformanceStat ( 2 ) )
] ) ;
var reactorItem = CatalogItem ( "ledger-reactor" , reactorPayload ) ;
reactorItem . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ capacitorItem , reactorItem ] , [ ] , [ ] ) ;
AetheriaRuntimeEnergySimulation . BeginTick ( entity , catalog ) ;
Require ( AetheriaRuntimeEnergySimulation . TryConsume ( entity , catalog , 5 ) ,
"online reactor must accept residual demand after capacitors drain" ) ;
var capacitor = entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Capacitor" ) ;
var reactor = entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Reactor" ) ;
RequireNear ( 0 , capacitor . CapacitorCharge , 0.000001 ,
"consumers must drain capacitors before adding reactor draw" ) ;
RequireNear ( 3 , reactor . ReactorDraw , 0.000001 ,
"residual demand must accumulate on the last-running reactor" ) ;
AetheriaRuntimeEnergySimulation . SettleReactors ( entity , catalog , 1 ) ;
RequireNear ( 1 , capacitor . CapacitorCharge , 0.000001 ,
"baseline reactor surplus must refill non-full capacitors after demand settles" ) ;
RequireNear ( 0 , reactor . ReactorDraw , 0.000001 ,
"reactor settlement must consume and reset the per-tick demand ledger" ) ;
RequireNear ( 283.5 , GridValue ( entity , "temperature" , 0 ) , 0.000001 ,
"capacitor discharge/refill losses and reactor baseline heat must reach canonical item cells" ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "energy-ledger-smoke" , CurrentZoneIndex = 0 , CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ]
} ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
var worldEntity = Flatten ( surface . Surface . Root ) . Single ( node = >
node . Id = = "aetheria.daemon.game.world.entity.0" ) ;
RequireEqual ( "1" , worldEntity . Props [ "capacitorCharge" ] ,
"Eve must expose the settled canonical capacitor charge" ) ;
RequireEqual ( "0" , worldEntity . Props [ "reactorDraw" ] ,
"Eve must expose the reset post-settlement reactor ledger" ) ;
}
private static void RadiatorPumpsHeatBeforeReactorSettlement ( )
{
var entity = Entity ( 0 , 0 , "player" ) ;
entity . HeatsinksEnabled = true ;
entity . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "radiator-capacitor" , Quality = 1 , Durability = 1 , Enabled = true } } ,
new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "radiator" , Quality = 1 , Durability = 1 , Enabled = true } }
] ;
entity . BehaviorStates =
[
new AetheriaRuntimeBehaviorStateCommit
{
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ,
OwnerIndex = 0 , BehaviorIndex = 0 , BehaviorKind = "Capacitor" , CapacitorCharge = 10
} ,
new AetheriaRuntimeBehaviorStateCommit
{
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ,
OwnerIndex = 1 , BehaviorIndex = 0 , BehaviorKind = "Radiator" , RadiatorTemperature = 280
}
] ;
entity . StatGrids =
[
Grid ( "hull" , 100 ) , Grid ( "shield" , 0 ) , Grid ( "heat" , 400 ) ,
Grid ( "temperature" , 400 ) , Grid ( "thermal-mass" , 1 ) , Grid ( "conductivity" , 1 )
] ;
var capacitor = CatalogItem ( "radiator-capacitor" , CapacitorPayload ( 10 , 1 ) ) ;
capacitor . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var radiatorPayload = new AetheriaRuntimeBehaviorPayload ( 0 , "Radiator" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , Number ( 300 ) ) ,
new AetheriaRuntimeBehaviorField ( 4 , PerformanceStat ( 0.5 ) ) ,
new AetheriaRuntimeBehaviorField ( 5 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 10 ) )
] ) ;
var radiator = CatalogItem ( "radiator" , radiatorPayload ) ;
radiator . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ capacitor , radiator ] , [ ] , [ ] ) ;
AetheriaRuntimeEnergySimulation . BeginTick ( entity , catalog ) ;
2026-07-17 03:14:26 +01:00
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , [ ] , catalog , 1 ) ;
2026-07-12 06:01:14 +01:00
AetheriaRuntimeEnergySimulation . StepRadiators ( entity , catalog , 1 ) ;
RequireNear ( 9 , entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Capacitor" ) . CapacitorCharge ,
0.000001 , "radiator pump must consume authored energy before reactor settlement" ) ;
RequireNear ( 300.5 , GridValue ( entity , "temperature" , 0 ) , 0.000001 ,
"radiator must remove pumped heat and return authored waste heat to its item cells" ) ;
RequireNear ( 290 , entity . BehaviorStates . Single ( value = > value . BehaviorKind = = "Radiator" ) . RadiatorTemperature ,
0.000001 , "pumped heat must accumulate in radiator thermal mass before radiation" ) ;
}
private static void EquipmentThermalPerformanceOwnsShutdownAndWear ( )
{
var entity = Entity ( 0 , 0 , "player" ) ;
entity . ShutdownPerformance = 0.25 ;
var item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "thermal-wear-item" , Quality = 0 , Durability = 10 , Enabled = true } ;
entity . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit { Item = item } ] ;
entity . StatGrids =
[
Grid ( "hull" , 100 ) , Grid ( "shield" , 0 ) , Grid ( "heat" , 300 ) ,
Grid ( "temperature" , 300 ) , Grid ( "thermal-mass" , 1 ) , Grid ( "conductivity" , 1 )
] ;
var wearPayload = new AetheriaRuntimeBehaviorPayload ( 0 , "Wear" , 0 ,
[ new AetheriaRuntimeBehaviorField ( 1 , new AetheriaRuntimeBehaviorValue (
"bool" , "" , 0 , true , "" , "" , [ ] , [ ] ) ) ] ) ;
var typed = CatalogItem ( "thermal-wear-item" , wearPayload ) ;
typed . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
typed . Durability = 10 ;
typed . ThermalResilience = 2 ;
typed . MinimumTemperature = 200 ;
typed . MaximumTemperature = 400 ;
typed . ThermalPerformanceCurveKeys =
[
new AetheriaRuntimeCurveKey ( 0 , 1 , 0 , 0 ) ,
new AetheriaRuntimeCurveKey ( 1 , 0 , 0 , 0 )
] ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ typed ] , [ ] , [ ] ) ;
AetheriaRuntimeThermalSimulation . UpdateEquipmentStates ( entity , catalog , 1 ) ;
var state = entity . EquipmentStates . Single ( ) ;
RequireNear ( 0.5 , state . ThermalPerformance , 0.000001 ,
"item thermal performance must come from mean occupied-cell temperature and authored curve" ) ;
Require ( state . ThermalOnline & & state . Online ,
"item above shutdown performance with positive durability must remain online" ) ;
2026-07-17 03:03:30 +01:00
AetheriaRuntimeBehaviorSimulation . Step ( 0 , [ entity ] , [ ] , catalog , 1 ) ;
2026-07-12 06:01:14 +01:00
RequireNear ( 10 - state . Wear , item . Durability , 0.000001 ,
"generic Wear behavior must apply the computed thermal wear potential at its authored cadence" ) ;
var temperature = entity . StatGrids . Single ( value = > value . Name = = "temperature" ) ;
temperature . Values = [ 380 ] ;
item . OverrideShutdown = false ;
entity . OverrideShutdown = true ;
AetheriaRuntimeThermalSimulation . UpdateEquipmentStates ( entity , catalog , 1 ) ;
state = entity . EquipmentStates . Single ( ) ;
Require ( ! state . ThermalOnline & & ! state . Online ,
"entity override alone must not bypass item thermal shutdown" ) ;
item . OverrideShutdown = true ;
AetheriaRuntimeThermalSimulation . UpdateEquipmentStates ( entity , catalog , 1 ) ;
Require ( entity . EquipmentStates . Single ( ) . ThermalOnline ,
"thermal shutdown bypass must require both entity-wide and item-local override" ) ;
}
private static void ThermalTopologyComesFromHullAndEquipment ( )
{
var entity = Entity ( 0 , 0 , "player" ) ;
entity . HullItemKey = "thermal-hull" ;
entity . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 0 , Y = 0 , Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "thermal-gear" , Quality = 1 , Durability = 1 , Enabled = true }
} ] ;
2026-07-17 00:46:58 +01:00
entity . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 1 , Y = 0 , Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "thermal-cargo-bay" , Quality = 1 , Durability = 1 , Enabled = true }
} ] ;
2026-07-12 06:01:14 +01:00
var hull = HullCatalogItem ( "thermal-hull" , 2 , 1 , 0 ) ;
hull . Mass = 10 ;
hull . SpecificHeat = 2 ;
hull . Conductivity = 4 ;
hull . InteriorShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var gear = CatalogItem ( "thermal-gear" ) ;
gear . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
gear . Mass = 4 ;
gear . SpecificHeat = 5 ;
gear . Conductivity = 3 ;
2026-07-17 00:46:58 +01:00
var cargoBay = CatalogItem ( "thermal-cargo-bay" ) ;
cargoBay . Category = AetheriaRuntimeItemCategories . CargoBay ;
cargoBay . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
cargoBay . Mass = 6 ;
cargoBay . SpecificHeat = 2 ;
cargoBay . Conductivity = 2 ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , gear , cargoBay ] , [ ] , [ ] ) ;
2026-07-12 06:01:14 +01:00
AetheriaRuntimeThermalSimulation . EnsureTopology ( entity , catalog ) ;
var mass = entity . StatGrids . Single ( value = > value . Name = = "thermal-mass" ) ;
var conductivity = entity . StatGrids . Single ( value = > value . Name = = "conductivity" ) ;
RequireNear ( 30 , mass . Values [ 0 ] , 0.000001 ,
"occupied cell thermal mass must include its proportional equipment mass" ) ;
2026-07-17 00:46:58 +01:00
RequireNear ( 22 , mass . Values [ 1 ] , 0.000001 ,
"typed cargo bays must contribute thermal mass at their authored hull cells" ) ;
2026-07-12 06:01:14 +01:00
RequireNear ( 3 , conductivity . Values [ 0 ] , 0.000001 ,
"occupied cell conductivity must come from installed equipment" ) ;
RequireNear ( 280 , entity . StatGrids . Single ( value = > value . Name = = "temperature" ) . Values [ 1 ] , 0.000001 ,
"authored hull topology must initialize each occupied cell at the fossil temperature" ) ;
}
2026-07-12 06:10:33 +01:00
private static void ThermalMedicalExposureUsesCockpitTemperature ( )
{
var entity = Entity ( 0 , 0 , "player" ) ;
entity . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "medical-cockpit" , Quality = 1 , Durability = 1 , Enabled = true }
} ] ;
entity . StatGrids =
[
Grid ( "hull" , 100 ) , Grid ( "temperature" , 340 ) ,
Grid ( "thermal-mass" , 1 ) , Grid ( "conductivity" , 1 )
] ;
var cockpit = CatalogItem ( "medical-cockpit" ,
new AetheriaRuntimeBehaviorPayload ( 0 , "Cockpit" , 0 , [ ] ) ) ;
cockpit . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ cockpit ] , [ ] , [ ] ) ;
var settings = AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ;
var heat = AetheriaRuntimeThermalMedicalSimulation . Step ( entity , catalog , 300 , settings ) ;
RequireNear ( 0.3 , entity . Heatstroke , 0.000001 ,
"cockpit heat must accumulate nonlinear heatstroke at the fossil rate" ) ;
Require ( heat . HeatstrokeRiskCrossed ,
"heatstroke must emit one upward severe-risk crossing" ) ;
RequireNear ( 340 , Stat ( entity , "cockpit-temperature" ) , 0.000001 ,
"cockpit cell temperature must become an authoritative Eve-readable fact" ) ;
entity . StatGrids . Single ( value = > value . Name = = "temperature" ) . Values = [ 280 ] ;
AetheriaRuntimeThermalMedicalSimulation . Step ( entity , catalog , 1 , settings ) ;
RequireNear ( 0.1 , entity . Heatstroke , 0.000001 ,
"heatstroke must recover linearly below the authored threshold" ) ;
entity . StatGrids . Single ( value = > value . Name = = "temperature" ) . Values = [ 263 ] ;
var cold = AetheriaRuntimeThermalMedicalSimulation . Step ( entity , catalog , 300 , settings ) ;
RequireNear ( 0.3 , entity . Hypothermia , 0.000001 ,
"cockpit cold must accumulate nonlinear hypothermia at the fossil rate" ) ;
Require ( cold . HypothermiaRiskCrossed ,
"hypothermia must use its own exposure for the intended severe-risk crossing" ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "thermal-medical-surface" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ]
} ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
var worldEntity = Flatten ( surface . Surface . Root ) . Single ( node = >
node . Id = = "aetheria.daemon.game.world.entity.0" ) ;
RequireEqual ( "263" , worldEntity . Props [ "cockpitTemperature" ] ,
"Eve must publish canonical cockpit temperature rather than deriving it from effects" ) ;
RequireEqual ( "true" , worldEntity . Props [ "hypothermiaRisk" ] ,
"Eve must publish the current severe cold-risk state" ) ;
Require ( worldEntity . Props . ContainsKey ( "heatstrokePostWeight" ) & &
worldEntity . Props . ContainsKey ( "severeHeatstrokeWeight" ) ,
"Eve must publish the exact source weights used by the original heatstroke presentation" ) ;
2026-07-12 06:18:00 +01:00
RequireEqual ( "5" , worldEntity . Props [ "heatstrokePhasingFrequency" ] ,
"Eve must publish the provider-authored severe heatstroke pulse frequency" ) ;
RequireEqual ( "1" , worldEntity . Props [ "deathTransitionSeconds" ] ,
"Eve must publish the original thermal death crossfade duration" ) ;
2026-07-12 06:10:33 +01:00
}
private static void ThermalMedicalDeathUsesOrdinaryDestructionPath ( )
{
var entity = Entity ( 0 , 0 , "player" ) ;
entity . EntityId = "thermal-pilot" ;
entity . Equipment = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "lethal-cockpit" , Quality = 1 , Durability = 1 , Enabled = true }
} ] ;
entity . StatGrids =
[
Grid ( "hull" , 100 ) , Grid ( "temperature" , 700 ) ,
Grid ( "thermal-mass" , 1 ) , Grid ( "conductivity" , 1 )
] ;
var cockpit = CatalogItem ( "lethal-cockpit" ,
new AetheriaRuntimeBehaviorPayload ( 0 , "Cockpit" , 0 , [ ] ) ) ;
cockpit . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ cockpit ] , [ ] , [ ] ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "thermal-death" , CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ]
} ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) , catalog , frameId : 17 ) ;
2026-07-12 06:10:33 +01:00
RequireEqual ( "heatstroke" , entity . CauseOfDeath ,
"lethal cockpit heat must persist the typed cause of death" ) ;
Require ( ! entity . IsActive & & ! string . IsNullOrWhiteSpace ( entity . DestructionId ) ,
"thermal death must enter the ordinary exactly-once destruction path" ) ;
var death = run . GameEvents . Single ( value = > value . Kind = = "entity.destroyed" ) ;
RequireEqual ( "heatstroke" , death . Reason ,
"Eve feedback must carry the thermal cause needed for the original death transition" ) ;
Require ( run . GameEvents . Any ( value = > value . Kind = = "pilot.heatstroke.risk" ) ,
"a lethal step crossing the severe threshold must publish risk before death" ) ;
}
2026-07-11 17:50:26 +01:00
private static void ThermalCellsUseFossilConductionAndRadiation ( )
{
var entity = Entity ( 7 , 0 , "player" ) ;
entity . StatGrids =
[
Grid ( AetheriaRuntimeThermalSimulation . TemperatureGrid , 2 , 1 , 300 , 280 ) ,
Grid ( AetheriaRuntimeThermalSimulation . ThermalMassGrid , 2 , 1 , 1 , 1 ) ,
Grid ( AetheriaRuntimeThermalSimulation . ConductivityGrid , 2 , 1 , 1 , 1 )
] ;
AetheriaRuntimeThermalSimulation . AddHeat ( entity , 20 ) ;
RequireNear ( 310 , GridValue ( entity , AetheriaRuntimeThermalSimulation . TemperatureGrid , 0 ) , 0.000001 ,
"heat energy must be divided across cells and thermal mass" ) ;
RequireNear ( 290 , GridValue ( entity , AetheriaRuntimeThermalSimulation . TemperatureGrid , 1 ) , 0.000001 ,
"heat energy must be divided across cells and thermal mass" ) ;
AetheriaRuntimeThermalSimulation . Step ( entity , 0.1 ) ;
var expectedHot = ( 310 / 0.01 + 290 ) / 101 ;
expectedHot - = Math . Pow ( expectedHot , 3 ) * 0.00000001 * 0.1 ;
var expectedCool = ( 290 / 0.01 + 310 ) / 101 ;
expectedCool - = Math . Pow ( expectedCool , 3 ) * 0.00000001 * 0.1 ;
RequireNear ( expectedHot , GridValue ( entity , AetheriaRuntimeThermalSimulation . TemperatureGrid , 0 ) , 0.000001 ,
"hot cell must follow fossil conduction and radiation" ) ;
RequireNear ( expectedCool , GridValue ( entity , AetheriaRuntimeThermalSimulation . TemperatureGrid , 1 ) , 0.000001 ,
"cool cell must follow fossil conduction and radiation" ) ;
RequireNear ( ( expectedHot + expectedCool ) / 2 , Stat ( entity , "heat" ) , 0.000001 ,
"legacy heat scalar must be derived from cell temperature" ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "thermal-projection-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.7" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ]
} ;
var document = AetheriaRuntimeGameDocuments . CurrentEntity ( new AetheriaRuntimeDaemonFrameDocument { Run = run } ) ;
RequireNear ( Stat ( entity , "heat" ) , document . Hud . MeanTemperature , 0.000001 ,
"Eve current-entity state must publish mean temperature" ) ;
RequireNear ( GridValue ( entity , AetheriaRuntimeThermalSimulation . TemperatureGrid , 0 ) , document . Hud . MaximumTemperature , 0.000001 ,
"Eve current-entity state must publish maximum temperature" ) ;
Require ( document . Hud . ThermalVisibility > 0 , "Eve current-entity state must publish thermal visibility" ) ;
2026-07-09 19:46:41 +01:00
}
2026-07-11 17:43:48 +01:00
private static void YmirMovesProjectileAndReportsStableContact ( )
2026-07-09 19:46:41 +01:00
{
2026-07-11 17:43:48 +01:00
var ( run , zone , target ) = Scenario ( ) ;
2026-07-15 03:52:56 +01:00
using var physics = NewPhysics ( ) ;
2026-07-14 22:25:05 +01:00
physics . RetainWorlds ( run . RunId , [ zone . ZoneIndex ] ) ;
physics . Step ( run . RunId , 0 , 0 , zone , zone . Entities , 0.1 ) ;
var step = physics . StepPhysicalPayloads ( run . RunId , 0 , 0 , zone , zone . Entities , 0.1 ) ;
2026-07-11 17:43:48 +01:00
2026-07-14 22:25:05 +01:00
RequireEqual ( "ymir.box3d.retained-session.v1" , physics . ImplementationId , "zone physics must identify its retained Ymir implementation" ) ;
2026-07-12 01:05:25 +01:00
RequireEqual ( 0 , step . PhysicalPayloads . Count , "contacted projectile must not survive" ) ;
2026-07-11 17:43:48 +01:00
RequireEqual ( 1 , step . Hits . Count , "Ymir must report one projectile contact" ) ;
RequireEqual ( target . EntityIndex , step . Hits [ 0 ] . TargetEntityIndex , "contact must resolve the daemon entity" ) ;
2026-07-12 01:05:25 +01:00
RequireEqual ( "aetheria.physical-payload.smoke-projectile" , step . Hits [ 0 ] . PhysicalPayloadBodyId , "physical payload body id must be stable" ) ;
2026-07-14 22:25:05 +01:00
RequireEqual ( "aetheria.daemon.entity.smoke.entity.2" , step . Hits [ 0 ] . TargetBodyId , "entity body id must be stable" ) ;
}
private static void PayloadQueryExcludesItsSource ( )
{
var source = Entity ( 1 , 0 , "player" ) ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ source ] ,
PhysicalPayloads =
[
new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = "source-exclusion" ,
SourceEntityIndex = source . EntityIndex ,
PositionX = 0 ,
PositionZ = 0 ,
VelocityX = 10 ,
Radius = 1 ,
LifetimeSeconds = 5 ,
Active = true
}
]
} ;
2026-07-15 03:52:56 +01:00
using var physics = NewPhysics ( ) ;
2026-07-14 22:25:05 +01:00
physics . RetainWorlds ( "source-exclusion-smoke" , [ zone . ZoneIndex ] ) ;
physics . Step ( "source-exclusion-smoke" , 1 , 0 , zone , zone . Entities , 0.1 ) ;
var step = physics . StepPhysicalPayloads ( "source-exclusion-smoke" , 1 , 0 , zone , zone . Entities , 0.1 ) ;
RequireEqual ( 0 , step . Hits . Count , "a payload query must not hit its source body" ) ;
RequireEqual ( 1 , step . PhysicalPayloads . Count , "source exclusion must leave the payload alive" ) ;
}
private static void PayloadBodiesDoNotCollideWithEachOther ( )
{
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ ] ,
PhysicalPayloads =
[
new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = "payload-left" ,
SourceEntityIndex = - 1 ,
PositionX = - 5 ,
VelocityX = 100 ,
Radius = 1 ,
LifetimeSeconds = 5 ,
Active = true
} ,
new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = "payload-right" ,
SourceEntityIndex = - 1 ,
PositionX = 5 ,
VelocityX = - 100 ,
Radius = 1 ,
LifetimeSeconds = 5 ,
Active = true
}
]
} ;
2026-07-15 03:52:56 +01:00
using var physics = NewPhysics ( ) ;
2026-07-14 22:25:05 +01:00
physics . RetainWorlds ( "payload-isolation-smoke" , [ zone . ZoneIndex ] ) ;
physics . Step ( "payload-isolation-smoke" , 2 , 0 , zone , zone . Entities , 0.1 ) ;
var step = physics . StepPhysicalPayloads ( "payload-isolation-smoke" , 2 , 0 , zone , zone . Entities , 0.1 ) ;
RequireEqual ( 0 , step . Hits . Count , "payload bodies must not manufacture world-query hits against each other" ) ;
RequireEqual ( 2 , step . PhysicalPayloads . Count , "payload bodies must survive crossing each other" ) ;
Require ( step . PhysicalPayloads . Single ( payload = > payload . PayloadId = = "payload-left" ) . VelocityX > 0 ,
"payload-to-payload response must not reverse the left payload" ) ;
Require ( step . PhysicalPayloads . Single ( payload = > payload . PayloadId = = "payload-right" ) . VelocityX < 0 ,
"payload-to-payload response must not reverse the right payload" ) ;
}
private static void OverlappingMineRemainsQueryableAfterArming ( )
{
var target = Entity ( 2 , 0 , "enemy" ) ;
var mine = new AetheriaRuntimePhysicalPayloadCommit
{
PayloadId = "arming-overlap" ,
PayloadKind = "mine" ,
SourceEntityIndex = 1 ,
PositionX = 0 ,
PositionZ = 0 ,
Radius = 1 ,
TriggerRadius = 25 ,
ActivationDelaySeconds = 1 ,
LifetimeSeconds = 10 ,
Stationary = false ,
Active = true
} ;
var zone = new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ target ] ,
PhysicalPayloads = [ mine ]
} ;
2026-07-15 03:52:56 +01:00
using var physics = NewPhysics ( ) ;
2026-07-14 22:25:05 +01:00
physics . RetainWorlds ( "mine-arming-overlap-smoke" , [ zone . ZoneIndex ] ) ;
physics . Step ( "mine-arming-overlap-smoke" , 1 , 0 , zone , zone . Entities , 0.5 ) ;
var unarmed = physics . StepPhysicalPayloads ( "mine-arming-overlap-smoke" , 1 , 0 , zone , zone . Entities , 0.5 ) ;
RequireEqual ( 1 , unarmed . Hits . Count , "an unarmed overlap may be observed without granting Ymir trigger authority" ) ;
mine . AgeSeconds = mine . ActivationDelaySeconds ;
mine . Radius = mine . TriggerRadius ;
zone . PhysicalPayloads = unarmed . PhysicalPayloads ;
physics . Step ( "mine-arming-overlap-smoke" , 2 , 0 , zone , zone . Entities , 0.5 ) ;
var armed = physics . StepPhysicalPayloads ( "mine-arming-overlap-smoke" , 2 , 0 , zone , zone . Entities , 0.5 ) ;
RequireEqual ( 1 , armed . Hits . Count ,
"a retained mine already overlapping at activation must still yield an eligible Box3D overlap fact" ) ;
RequireEqual ( target . EntityIndex , armed . Hits [ 0 ] . TargetEntityIndex ,
"the armed overlap fact must preserve the target identity" ) ;
2026-07-09 19:46:41 +01:00
}
2026-07-12 00:49:00 +01:00
private static void DaemonSimulationTreatsYmirHitAsPresentationOnly ( )
2026-07-09 19:46:41 +01:00
{
2026-07-11 17:43:48 +01:00
var ( run , _ , target ) = Scenario ( ) ;
2026-07-09 19:46:41 +01:00
2026-07-11 17:43:48 +01:00
AetheriaRuntimeDaemonSimulation . Step (
run ,
new AetheriaRuntimeDaemonIntentState ( ) ,
0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
2026-07-15 03:52:56 +01:00
NewPhysics ( ) ) ;
2026-07-09 19:46:41 +01:00
2026-07-12 00:49:00 +01:00
RequireEqual ( 100.0 , Stat ( target , "hull" ) , "presentation projectile contact must not write combat damage" ) ;
2026-07-12 01:05:25 +01:00
RequireEqual ( 0 , run . Zones [ 0 ] . PhysicalPayloads . Count , "spent projectile must leave daemon state" ) ;
RequireEqual ( 1 , run . GameEvents . Count ( value = > value . Kind = = "physical-payload.contact" & & value . SubjectKey = = "smoke-projectile" ) ,
2026-07-11 19:22:14 +01:00
"Ymir contact must emit one projectile-identity impact event" ) ;
2026-07-12 00:49:00 +01:00
RequireEqual ( 0 , run . GameEvents . Count ( value = > value . Kind = = "entity.damaged" & & value . TargetEntityIndex = = target . EntityIndex ) ,
"presentation projectile contact must not manufacture a damage event" ) ;
2026-07-11 19:22:14 +01:00
var feedback = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 0 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
2026-07-12 01:05:25 +01:00
Require ( Flatten ( feedback . Surface . Root ) . Any ( node = > node . Kind = = "feedback.event" & & node . Props [ "eventKind" ] = = "physical-payload.contact" & & node . Props [ "subjectKey" ] = = "smoke-projectile" ) ,
2026-07-11 19:22:14 +01:00
"Eve feedback must project authoritative projectile impact identity" ) ;
}
2026-07-12 00:49:00 +01:00
private static void ProjectileContactCannotKill ( )
2026-07-11 19:22:14 +01:00
{
var ( run , _ , target ) = Scenario ( ) ;
target . StatGrids . Single ( grid = > grid . Name = = "hull" ) . Values = [ 5 ] ;
AetheriaRuntimeDaemonSimulation . Step ( run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
2026-07-15 03:52:56 +01:00
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault , NewPhysics ( ) , frameId : 9 ) ;
2026-07-12 00:49:00 +01:00
Require ( target . IsActive & & Math . Abs ( Stat ( target , "hull" ) - 5 ) < 0.000001 ,
"even nominally lethal presentation contact must leave canonical target state untouched" ) ;
RequireEqual ( 0 , run . GameEvents . Count ( value = > value . Kind = = "entity.destroyed" & & value . TargetEntityIndex = = target . EntityIndex ) ,
"presentation contact must not manufacture a destruction event" ) ;
2026-07-09 19:46:41 +01:00
}
2026-07-11 19:02:42 +01:00
private static void MissingWorldPhysicsOwnerCannotAdvanceShips ( )
{
var entity = Entity ( 0 , 0 , "player" ) ;
entity . VelocityX = 10 ;
var run = new AetheriaRuntimeRunCheckpointCommit { CurrentZoneIndex = 0 , CurrentEntityKey = "zone.0.entity.0" , Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ entity ] } ] } ;
try
{
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-missing-world-physics.cc" ) , run ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonTickOptions { FrameId = 1 , FixedDeltaSeconds = 0.1 , BuildPublications = false } ) ;
2026-07-11 19:02:42 +01:00
}
catch ( InvalidOperationException )
{
RequireNear ( 0 , entity . PositionX , 0.000001 , "ship must not advance without Ymir world authority" ) ;
return ;
}
throw new InvalidOperationException ( "daemon advanced a ship without an authoritative world physics owner" ) ;
}
2026-07-11 19:05:11 +01:00
private static void TractorRampsAndPullsThroughYmirWithoutTeleportingCargo ( )
{
var ship = Entity ( 0 , 0 , "player" ) ;
2026-07-11 19:11:46 +01:00
ship . DirectionX = 1 ; ship . DirectionY = 0 ;
var pickup = new AetheriaRuntimeDroppedPickupCommit { PickupIndex = 3 , PositionX = 60 , Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "salvage" , Quantity = 1 } , LifetimeSeconds = 30 } ;
var run = new AetheriaRuntimeRunCheckpointCommit { CurrentZoneIndex = 0 , CurrentEntityKey = "zone.0.entity.0" , Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship ] , DroppedPickups = [ pickup ] } ] } ;
2026-07-11 19:05:11 +01:00
var command = AetheriaRuntimeDaemonCommandDocument . Create ( AetheriaRuntimeDaemonCommandKinds . SetTractorPower , "pilot" , "tractor-smoke" , 0 , "zone.0.entity.0" ) ;
command . CommandId = "tractor-on" ; command . ScalarValue = 1 ;
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-tractor-smoke.cc" ) , run ,
2026-07-15 03:52:56 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = NewPhysics ( ) , FrameId = 1 , FixedDeltaSeconds = 0.25 , SimulationTimeSeconds = 0.25 , ObservedCommands = [ command ] , BuildPublications = false } ) ;
2026-07-11 19:05:11 +01:00
RequireNear ( 0.5 , ship . TractorPower , 0.000001 , "tractor power must use the fossil two-per-second ramp" ) ;
2026-07-11 19:11:46 +01:00
Require ( pickup . VelocityX < 0 & & pickup . PositionX < 60 , "Ymir must pull a pickup inside the forward tractor volume toward the ship" ) ;
RequireEqual ( 1 , pickup . Item . Quantity , "tractor force must not consume the pickup item" ) ;
2026-07-11 19:05:11 +01:00
RequireEqual ( 0 , CargoQuantity ( ship , "salvage" ) , "scooping must remain a separate capacity-checked transaction" ) ;
2026-07-15 03:52:56 +01:00
Require ( pickup . AgeSeconds > 0 & & pickup . AgeSeconds < pickup . LifetimeSeconds ,
"daemon-owned pickup lifetime must advance independently of its SoA presentation" ) ;
2026-07-15 11:26:49 +01:00
var release = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . SetTractorPower ,
"pilot" ,
"tractor-smoke" ,
1 ,
"zone.0.entity.0" ) ;
release . CommandId = "tractor-off" ;
release . ScalarValue = 0 ;
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-tractor-release-smoke.cc" ) , run ,
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = NewPhysics ( ) , FrameId = 2 , FixedDeltaSeconds = 0.25 , SimulationTimeSeconds = 0.5 , ObservedCommands = [ release ] , BuildPublications = false } ) ;
RequireNear ( 0 , ship . TractorTargetPower , 0.000001 , "released tractor input must set daemon target power to zero" ) ;
RequireNear ( 0 , ship . TractorPower , 0.000001 , "daemon must ramp released tractor power back to zero at the fossil rate" ) ;
var inputCapability = AetheriaRuntimeInputCapabilityDocument
. FromFrame ( new AetheriaRuntimeDaemonFrameDocument { FrameId = 2 , Run = run } )
. ToEveDocument ( ) ;
var scoopAction = inputCapability . Actions . Single ( action = > action . ActionId = = "pilot.scoop" ) ;
Require ( scoopAction . InputValue ? . Model = = "button-hold.v1" & &
scoopAction . InputValue . PayloadKey = = "scalarValue" & &
scoopAction . Payload [ "scalarValue" ] = = "0" ,
"tractor input must advertise press/release scalar ownership instead of a one-shot on command" ) ;
ship . TractorPower = 0.5 ;
ship . TractorTargetPower = 1 ;
2026-07-15 11:03:45 +01:00
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
var beam = Flatten ( surface . Surface . Root ) . Single ( node = > node . Kind = = "beam.presentation" ) ;
Require ( beam . Props [ "sourceEntityId" ] = = run . EntityRecordKey ( 0 , ship . EntityIndex ) & &
beam . Props [ "assetRole" ] = = "effect.beam.tractor" & &
beam . Props [ "directionMode" ] = = "source-forward.v1" & &
beam . Props [ "activationActionId" ] = = "pilot.scoop" & &
beam . Props [ "power" ] = = "0.5" & & beam . Props [ "radius" ] = = "25" & &
beam . Props [ "maximumDistance" ] = = "75" ,
"Eve beam presentation must project the same daemon tractor power and fossil volume without owning force or contact" ) ;
2026-07-15 05:30:06 +01:00
double PulledVelocity ( double power , int frameId )
{
var actor = Entity ( 0 , 0 , "player" ) ;
actor . DirectionX = 1 ;
actor . DirectionY = 0 ;
actor . TractorPower = power ;
actor . TractorTargetPower = power ;
var cargo = new AetheriaRuntimeDroppedPickupCommit
{
PickupIndex = 30 + frameId ,
PositionX = 60 ,
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = "salvage" , Quantity = 1 } ,
LifetimeSeconds = 30
} ;
var scenario = new AetheriaRuntimeRunCheckpointCommit
{
RunId = $"tractor-power-{frameId}" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ actor ] , DroppedPickups = [ cargo ] } ]
} ;
AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , $"aetheria-tractor-power-{frameId}.cc" ) ,
scenario ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = NewPhysics ( ) , FrameId = frameId , FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = frameId * 0.1 , BuildPublications = false
} ) ;
return cargo . VelocityX ;
}
RequireNear ( PulledVelocity ( 0.02 , 20 ) , PulledVelocity ( 1 , 21 ) , 0.000001 ,
"tractor power above the fossil threshold must gate full traction rather than scale force" ) ;
2026-07-11 19:17:13 +01:00
var pickupAsset = AetheriaRuntimeAssets . ProjectManifest ( null ) . Assets . Single ( asset = > asset . Ref . AssetKey = = "prefab.entity.pickup" ) ;
Require ( pickupAsset . Ref . Metadata . TryGetValue ( "unityAssetPath" , out var pickupPath ) & & pickupPath = = "Assets/Prefabs/RPG/Pickups/Tetrahedron.prefab" ,
2026-07-11 19:14:38 +01:00
"provider asset manifest must advertise the pickup visual used by Eve" ) ;
2026-07-12 01:24:30 +01:00
var assets = AetheriaRuntimeAssets . ProjectManifest ( null ) . Assets ;
var playerAsset = assets . Single ( asset = > asset . Ref . AssetKey = = "prefab.entity.player" ) ;
RequireEqual ( "player" , playerAsset . Ref . Metadata [ "presentationRole" ] ,
"entity prefab fallback must use a specific presentation role instead of the generic world tag" ) ;
2026-07-12 01:29:28 +01:00
var boltEffect = assets . Single ( asset = > asset . Ref . AssetKey = = "prefab.effect.shot.bolt" ) ;
RequireEqual ( "effect.shot.bolt" , boltEffect . Ref . Metadata [ "presentationRole" ] ,
"provider manifest must bind semantic shot feedback to its graduated EveUnity effect" ) ;
2026-07-15 11:03:45 +01:00
var tractorEffect = assets . Single ( asset = > asset . Ref . AssetKey = = "prefab.effect.beam.tractor" ) ;
RequireEqual ( "effect.beam.tractor" , tractorEffect . Ref . Metadata [ "presentationRole" ] ,
"provider manifest must bind the stripped fossil tractor prefab to the generic beam role" ) ;
2026-07-12 06:43:33 +01:00
var thermalProfiles = assets . Where ( asset = >
2026-07-16 01:56:29 +01:00
string . Equals ( asset . Ref . Kind , AetheriaRuntimeAssetKinds . VolumeProfile , StringComparison . Ordinal ) & &
asset . Ref . Metadata . TryGetValue ( "presentationRole" , out var role ) & &
( role . StartsWith ( "post.thermal." , StringComparison . Ordinal ) | |
string . Equals ( role , "post.death" , StringComparison . Ordinal ) ) ) . ToArray ( ) ;
2026-07-12 06:43:33 +01:00
RequireEqual ( 5 , thermalProfiles . Length ,
"provider manifest must advertise every original thermal and death volume profile" ) ;
Require ( thermalProfiles . All ( asset = >
asset . Ref . Metadata . ContainsKey ( "unityAssetPath" ) & &
asset . Ref . Metadata . ContainsKey ( "presentationRole" ) ) ,
"thermal profiles must cross the CDN boundary with exact Unity paths and semantic roles" ) ;
2026-07-11 19:05:11 +01:00
}
2026-07-11 19:07:29 +01:00
private static void PickupIsCapacityCheckedExactlyOnceAndExpires ( )
{
var hull = CatalogItem ( "pickup-hull" ) ; hull . HullCapacity = PerformanceStat ( 1 ) ;
var salvage = CatalogItem ( "salvage" ) ; salvage . Volume = 1 ;
2026-07-14 01:03:34 +01:00
var cargoBay = CatalogItem ( "pickup-cargo-bay" ) ; cargoBay . InteriorOccupiedCells = 1 ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , salvage , cargoBay ] , [ ] , [ ] ) ;
2026-07-11 19:07:29 +01:00
var ship = Entity ( 0 , 0 , "player" ) ; ship . HullItemKey = hull . ItemKey ; ship . CargoContents = [ Cargo ( ) ] ;
2026-07-17 00:46:58 +01:00
ship . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 } } ] ;
2026-07-11 19:07:29 +01:00
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship ] , DroppedPickups = [ new AetheriaRuntimeDroppedPickupCommit { PickupIndex = 7 , PositionX = 10 , Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = salvage . ItemKey , Quantity = 1 } , LifetimeSeconds = 30 } ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit { CurrentZoneIndex = 0 , CurrentEntityKey = "zone.0.entity.0" , Zones = [ zone ] } ;
2026-07-14 01:03:34 +01:00
var forbiddenCommand = AetheriaRuntimeDaemonCommandDocument . Create ( AetheriaRuntimeDaemonCommandKinds . PickUpLoot , "pilot" , "pickup-smoke" , 0 , "zone.0.entity.0" ) ;
forbiddenCommand . CommandId = "pickup-command-forbidden" ;
forbiddenCommand . TargetEntityKey = "zone.0.entity.0" ;
var forbidden = AetheriaRuntimeDaemonOperations . Execute ( run , [ forbiddenCommand ] , new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ) ;
Require ( forbidden . RejectedCommandIds . Contains ( forbiddenCommand . CommandId ) ,
"client pickup commands must not own cargo collection" ) ;
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-pickup-no-contact.cc" ) , run ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = new ScriptedWorldPhysics ( ) , FrameId = 1 , FixedDeltaSeconds = 0.1 , SimulationTimeSeconds = 0.1 , Catalog = catalog , BuildPublications = false } ) ;
2026-07-14 01:03:34 +01:00
RequireEqual ( 1 , zone . DroppedPickups . Count , "nearby pickup without a Ymir contact fact must remain in the world" ) ;
RequireEqual ( 0 , CargoQuantity ( ship , salvage . ItemKey ) , "proximity must not mutate cargo" ) ;
2026-07-15 08:09:29 +01:00
var forgedContact = new AetheriaRuntimeWorldBeginContact
{
FactId = "ymir-fact-forged-identity" ,
EntityAIndex = 0 ,
EntityAId = "another-entity" ,
PickupIndex = 7 ,
NormalX = 1
} ;
var rejectedForgedIdentity = false ;
try
{
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-pickup-forged-identity.cc" ) , run ,
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = new ScriptedWorldPhysics ( forgedContact ) , FrameId = 2 , FixedDeltaSeconds = 0.1 , SimulationTimeSeconds = 0.2 , Catalog = catalog , BuildPublications = false } ) ;
}
catch ( InvalidOperationException )
{
rejectedForgedIdentity = true ;
}
Require ( rejectedForgedIdentity , "a Ymir contact whose stable identity disagrees with the live entity must fail closed" ) ;
RequireEqual ( 1 , zone . DroppedPickups . Count , "forged contact identity must not remove the pickup" ) ;
RequireEqual ( 0 , CargoQuantity ( ship , salvage . ItemKey ) , "forged contact identity must not mutate cargo" ) ;
RequireEqual ( 0 , run . PickupContactReceipts . Count , "forged contact identity must not mint a consumption receipt" ) ;
2026-07-14 21:38:46 +01:00
var contact = new AetheriaRuntimeWorldBeginContact
{
FactId = "ymir-fact-pickup-7" ,
EntityAIndex = 0 ,
2026-07-15 08:09:29 +01:00
EntityAId = ship . EntityId ,
2026-07-14 21:38:46 +01:00
PickupIndex = 7 ,
NormalX = 1
} ;
2026-07-14 01:03:34 +01:00
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-pickup-contact-dedup.cc" ) , run ,
2026-07-15 08:09:29 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = new ScriptedWorldPhysics ( contact , contact ) , FrameId = 3 , FixedDeltaSeconds = 0.1 , SimulationTimeSeconds = 0.3 , Catalog = catalog , BuildPublications = false } ) ;
2026-07-14 01:03:34 +01:00
RequireEqual ( 0 , zone . DroppedPickups . Count , "one Ymir contact must consume the pickup" ) ;
RequireEqual ( 1 , CargoQuantity ( ship , salvage . ItemKey ) , "duplicate contact facts must commit cargo exactly once" ) ;
RequireEqual ( 1 , run . GameEvents . Count ( value = > value . Kind = = "pickup.collected" & & value . PickupIndex = = 7 ) ,
"duplicate contact facts must emit one collection event" ) ;
2026-07-15 16:36:13 +01:00
var collectionEvent = run . GameEvents . Single ( value = > value . Kind = = "pickup.collected" & & value . PickupIndex = = 7 ) ;
RequireNear ( 1 , collectionEvent . ScalarValue , 0.000001 ,
"collection feedback must publish the committed cargo delta" ) ;
RequireNear ( 0 , collectionEvent . AuxiliaryValue , 0.000001 ,
"collection feedback must publish cargo quantity before the transaction" ) ;
2026-07-14 21:38:46 +01:00
RequireEqual ( 1 , run . PickupContactReceipts . Count ( value = > value . FactId = = contact . FactId ) ,
"duplicate delivery of one Ymir fact must persist one Aetheria consumption receipt" ) ;
2026-07-15 16:36:13 +01:00
var collectionFeedback = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 3 , Run = run } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
Require ( Flatten ( collectionFeedback . Surface . Root ) . Any ( node = > node . Kind = = "feedback.event" & &
node . Props [ "eventKind" ] = = "pickup.collected" & & node . Props [ "pickupIndex" ] = = "7" & &
node . Props [ "itemKey" ] = = salvage . ItemKey & & node . Props [ "scalarValue" ] = = "1" & &
node . Props [ "cargoQuantityBefore" ] = = "0" & & node . Props [ "cargoQuantityAfter" ] = = "1" ) ,
"Eve feedback must publish the exact cargo delta committed by one Ymir contact fact" ) ;
2026-07-11 19:07:29 +01:00
zone . DroppedPickups = [ new AetheriaRuntimeDroppedPickupCommit { PickupIndex = 8 , PositionX = 10 , Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = salvage . ItemKey , Quantity = 1 } , LifetimeSeconds = 30 } ] ;
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-pickup-expiry-smoke.cc" ) , run ,
2026-07-15 08:09:29 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = new ScriptedWorldPhysics ( ) , FrameId = 4 , FixedDeltaSeconds = 30 , SimulationTimeSeconds = 30 , BuildPublications = false } ) ;
2026-07-11 19:07:29 +01:00
RequireEqual ( 0 , zone . DroppedPickups . Count , "pickup must expire after the fossil thirty-second lifetime" ) ;
2026-07-11 19:19:47 +01:00
Require ( run . GameEvents . Any ( value = > value . Kind = = "pickup.expired" & & value . PickupIndex = = 8 ) ,
"daemon lifetime owner must emit authoritative pickup expiry event" ) ;
2026-07-11 19:07:29 +01:00
}
2026-07-15 20:46:05 +01:00
private static void TradePurchaseDerivesAcceptanceFromDaemonState ( )
{
2026-07-17 06:40:51 +01:00
var ore = CatalogItem ( "trade-ore" ) ;
ore . Price = 40 ;
ore . Volume = 1 ;
ore . Stackable = true ;
ore . MaxStack = 4 ;
ore . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var cargoBay = CatalogItem ( "trade-cargo-bay" ) ;
cargoBay . InteriorShapeWidth = 3 ;
cargoBay . InteriorShapeHeight = 1 ;
cargoBay . InteriorOccupiedCells = 3 ;
cargoBay . InteriorShapeCells =
[
new AetheriaRuntimeShapeCell ( 0 , 0 ) ,
new AetheriaRuntimeShapeCell ( 1 , 0 ) ,
new AetheriaRuntimeShapeCell ( 2 , 0 )
] ;
2026-07-15 20:46:05 +01:00
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ ore , cargoBay ] , [ ] , [ ] ) ;
var station = Entity ( 0 , 0 , "station" ) ;
station . Kind = "station" ;
2026-07-17 06:40:51 +01:00
station . CargoContents = [ Cargo ( ( ore . ItemKey , 4 , 2 , 3 ) , ( ore . ItemKey , 4 , 3 , 3 ) ) ] ;
2026-07-15 20:46:05 +01:00
station . DockingBayAssignments = [ 1 ] ;
station . ChildEntityIndices = [ 1 ] ;
var ship = Entity ( 1 , 0 , "player" ) ;
2026-07-17 00:46:58 +01:00
ship . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit
2026-07-15 20:46:05 +01:00
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
} ] ;
2026-07-17 06:40:51 +01:00
ship . CargoContents = [ Cargo ( ( ore . ItemKey , 3 , 0 , 0 ) ) ] ;
2026-07-15 20:46:05 +01:00
var zone = new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ station , ship ] } ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "trade-authority-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.1" ,
Credits = 5000 ,
Zones = [ zone ]
} ;
var command = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . TradePurchase ,
"pilot" ,
"trade-authority-smoke" ,
1 ,
run . CurrentEntityKey ) ;
command . TradePurchase . ItemKey = ore . ItemKey ;
2026-07-17 06:40:51 +01:00
command . TradePurchase . Quantity = 4 ;
2026-07-15 20:46:05 +01:00
command . TradePurchase . StationCargoIndex = 0 ;
command . TradePurchase . TargetCargoIndex = 0 ;
command . TradePurchase . SourceX = 2 ;
command . TradePurchase . SourceY = 3 ;
command . TradePurchase . PurchaseKind = "docked_ship" ;
command . TradePurchase . UnitPrice = - 999 ;
command . TradePurchase . TotalPrice = - 999 ;
command . TradePurchase . StationEntityKey = "forged-station" ;
command . TradePurchase . TargetEntityKey = "forged-target" ;
command . TradePurchase . CreatesDockedShip = true ;
Require ( AetheriaRuntimeRunCheckpointCommit . TryParseEntityKey ( run . CurrentEntityKey , out _ , out _ ) ,
"trade smoke current entity key must be daemon-resolvable" ) ;
2026-07-17 06:40:51 +01:00
RequireEqual ( 0 , AetheriaRuntimeCargoCapacityQueries . UnitsThatFit ( ship , catalog , ore . ItemKey , 0 ) ,
"the old volume-only capacity proxy must expose why it cannot own spatial stack placement" ) ;
2026-07-15 20:46:05 +01:00
var daemonUnitPrice = AetheriaRuntimeDaemonTradeItemQueries . TradeItemValue (
ore ,
station . CargoContents [ 0 ] . Items [ 0 ] . Item ,
catalog . TradeValueSettings ) . Price ;
Require ( daemonUnitPrice > 0 , "trade smoke daemon catalog price must be positive" ) ;
var result = AetheriaRuntimeDaemonOperations . Execute (
run ,
[command] ,
new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ) ;
Require ( result . AppliedCommandIds . Contains ( command . CommandId ) ,
"daemon must accept a valid commodity purchase regardless of forged compatibility opinions" ) ;
2026-07-17 06:40:51 +01:00
RequireEqual ( 5000 - daemonUnitPrice * 4 , run . Credits ,
2026-07-15 20:46:05 +01:00
"daemon catalog price must own trade credit mutation" ) ;
2026-07-17 06:40:51 +01:00
RequireEqual ( 7 , CargoQuantity ( ship , ore . ItemKey ) , "daemon cargo capacity and placement must own delivery" ) ;
Require ( ship . CargoContents . Single ( ) . Items
. Where ( slot = > slot . Item . ItemKey = = ore . ItemKey )
. Select ( slot = > ( slot . X , slot . Y , slot . Item . Quantity ) )
. SequenceEqual ( [ ( 0 , 0 , 4 ) , ( 1 , 0 , 3 ) ] ) ,
"a purchase must fill an existing stack before placing the remainder in the first authored free cell" ) ;
2026-07-15 20:46:05 +01:00
RequireEqual ( 2 , zone . Entities . Count , "forged ship-creation opinion must not materialize an entity" ) ;
2026-07-17 06:32:28 +01:00
AetheriaRuntimeDaemonCommandDocument Contender ( string clientId , string commandId )
{
var contender = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . TradePurchase ,
clientId ,
run . RunId ,
2 ,
run . CurrentEntityKey ) ;
contender . CommandId = commandId ;
contender . TradePurchase . ItemKey = ore . ItemKey ;
2026-07-17 06:40:51 +01:00
contender . TradePurchase . Quantity = 4 ;
2026-07-17 06:32:28 +01:00
contender . TradePurchase . StationCargoIndex = 0 ;
contender . TradePurchase . TargetCargoIndex = 0 ;
2026-07-17 06:40:51 +01:00
contender . TradePurchase . SourceX = 3 ;
2026-07-17 06:32:28 +01:00
contender . TradePurchase . SourceY = 3 ;
return contender ;
}
var firstClient = Contender ( "pilot-a" , "trade-contested-a" ) ;
var secondClient = Contender ( "pilot-b" , "trade-contested-b" ) ;
var creditsBeforeContest = run . Credits ;
var contested = AetheriaRuntimeDaemonOperations . Execute (
run ,
[firstClient, secondClient] ,
new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ) ;
Require ( contested . AppliedCommandIds . SequenceEqual ( [ firstClient . CommandId ] ) ,
"the daemon batch reducer must serialize contested stock to exactly one winner" ) ;
Require ( contested . RejectedCommandIds . SequenceEqual ( [ secondClient . CommandId ] ) ,
"the command observing exhausted stock must be rejected exactly once" ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . TradeStockUnavailable ,
contested . RejectedCommandReasons [ secondClient . CommandId ] ,
"contested stock must retain the exact daemon-owned rejection reason" ) ;
2026-07-17 06:40:51 +01:00
RequireEqual ( creditsBeforeContest - daemonUnitPrice * 4 , run . Credits ,
2026-07-17 06:32:28 +01:00
"contested stock must debit the shared run wallet exactly once" ) ;
2026-07-17 06:40:51 +01:00
RequireEqual ( 11 , CargoQuantity ( ship , ore . ItemKey ) ,
2026-07-17 06:32:28 +01:00
"contested stock must deliver exactly one winning stack quantity" ) ;
RequireEqual ( 0 , CargoQuantity ( station , ore . ItemKey ) ,
"the winning purchase must exhaust authoritative station stock" ) ;
var frame = AetheriaRuntimeDaemonFrameDocument . Create (
run , "daemon" , "trade-contest" , 2 , 0.04 , 0.02 ) ;
frame . AppliedCommandIds = contested . AppliedCommandIds ;
frame . RejectedCommandIds = contested . RejectedCommandIds ;
frame . RejectedCommandReasons = contested . RejectedCommandReasons ;
var winnerFact = AetheriaRuntimeCommittedCommandFactDocument . FromAppliedCommand (
frame , firstClient , "aetheria.local" ) ;
var loserFact = AetheriaRuntimeCommittedCommandFactDocument . FromRejectedCommand (
frame , secondClient , "aetheria.local" ) ;
var winnerReceipt = AetheriaRuntimeDaemonReceiptProjector . Project (
winnerFact , AetheriaRuntimeDaemonGameSurfaceBuilder . SurfaceId ) ;
var loserReceipt = AetheriaRuntimeDaemonReceiptProjector . Project (
loserFact , AetheriaRuntimeDaemonGameSurfaceBuilder . SurfaceId ) ;
RequireEqual ( "reconciled" , winnerReceipt . State ,
"the winning client must receive an authoritative generic Eve receipt" ) ;
Require ( loserReceipt . State = = "denied" & &
loserReceipt . Message . Contains (
AetheriaRuntimeDaemonRejectionReasons . TradeStockUnavailable ,
StringComparison . Ordinal ) ,
"the losing client must receive the exact contested-stock reason through generic Eve" ) ;
var root = Path . Combine ( Path . GetTempPath ( ) , "aetheria-trade-contest-" + Guid . NewGuid ( ) . ToString ( "N" ) ) ;
Directory . CreateDirectory ( root ) ;
var statePath = Path . Combine ( root , "world.cc" ) ;
try
{
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > (
AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReplaceAsync ( frame ) . GetAwaiter ( ) . GetResult ( ) ;
node . MutableDocument < AetheriaRuntimeCommittedCommandFactDocument > (
new CultRecordKey ( AetheriaRuntimeCommittedCommandFactDocument . CreateRecordKey ( winnerFact . FactId ) ) )
. ReplaceAsync ( winnerFact ) . GetAwaiter ( ) . GetResult ( ) ;
node . MutableDocument < AetheriaRuntimeCommittedCommandFactDocument > (
new CultRecordKey ( AetheriaRuntimeCommittedCommandFactDocument . CreateRecordKey ( loserFact . FactId ) ) )
. ReplaceAsync ( loserFact ) . GetAwaiter ( ) . GetResult ( ) ;
node . FlushAsync ( soft : false ) . GetAwaiter ( ) . GetResult ( ) ;
}
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
var durableFrame = node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > (
AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReadAsync ( ) . GetAwaiter ( ) . GetResult ( )
? ? throw new InvalidOperationException ( "Durable contested-trade frame is missing." ) ;
var durableWinner = node . MutableDocument < AetheriaRuntimeCommittedCommandFactDocument > (
new CultRecordKey ( AetheriaRuntimeCommittedCommandFactDocument . CreateRecordKey ( winnerFact . FactId ) ) )
. ReadAsync ( ) . GetAwaiter ( ) . GetResult ( )
? ? throw new InvalidOperationException ( "Durable winning trade fact is missing." ) ;
var durableLoser = node . MutableDocument < AetheriaRuntimeCommittedCommandFactDocument > (
new CultRecordKey ( AetheriaRuntimeCommittedCommandFactDocument . CreateRecordKey ( loserFact . FactId ) ) )
. ReadAsync ( ) . GetAwaiter ( ) . GetResult ( )
? ? throw new InvalidOperationException ( "Durable rejected trade fact is missing." ) ;
var durableStation = durableFrame . Run . Zones . Single ( ) . Entities . Single ( entity = > entity . EntityIndex = = 0 ) ;
var durableShip = durableFrame . Run . Zones . Single ( ) . Entities . Single ( entity = > entity . EntityIndex = = 1 ) ;
RequireEqual ( run . Credits , durableFrame . Run . Credits ,
"CultCache reconnect must preserve the single authoritative debit" ) ;
RequireEqual ( 0 , CargoQuantity ( durableStation , ore . ItemKey ) ,
"CultCache reconnect must not resurrect contested station stock" ) ;
2026-07-17 06:40:51 +01:00
RequireEqual ( 11 , CargoQuantity ( durableShip , ore . ItemKey ) ,
2026-07-17 06:32:28 +01:00
"CultCache reconnect must preserve the winning cargo delivery exactly once" ) ;
RequireEqual ( "reconciled" , AetheriaRuntimeDaemonReceiptProjector . Project (
durableWinner , AetheriaRuntimeDaemonGameSurfaceBuilder . SurfaceId ) . State ,
"the winning generic Eve receipt must survive reconnect" ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . TradeStockUnavailable ,
durableLoser . RejectionReason ,
"the losing generic Eve receipt reason must survive reconnect" ) ;
}
}
finally
{
if ( Directory . Exists ( root ) )
Directory . Delete ( root , recursive : true ) ;
}
2026-07-15 20:46:05 +01:00
}
2026-07-17 01:06:25 +01:00
private static void TradeSaleIsDaemonPricedSpatialAndAtomic ( )
{
var ore = CatalogItem ( "sale-ore" ) ;
ore . Price = 40 ;
ore . Stackable = true ;
ore . MaxStack = 10 ;
ore . ShapeWidth = 1 ;
ore . ShapeHeight = 1 ;
ore . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
var cargoBay = CatalogItem ( "sale-cargo-bay" ) ;
cargoBay . InteriorShapeWidth = 2 ;
cargoBay . InteriorShapeHeight = 1 ;
cargoBay . InteriorShapeCells =
[
new AetheriaRuntimeShapeCell ( 0 , 0 ) ,
new AetheriaRuntimeShapeCell ( 1 , 0 )
] ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ ore , cargoBay ] , [ ] , [ ] ) ;
var station = Entity ( 0 , 0 , "station" ) ;
station . Kind = "station" ;
station . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
} ] ;
station . CargoContents = [ Cargo ( ( ore . ItemKey , 8 , 0 , 0 ) ) ] ;
station . DockingBayAssignments = [ 1 ] ;
var ship = Entity ( 1 , 0 , "player" ) ;
ship . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
} ] ;
ship . CargoContents = [ new AetheriaRuntimeCargoBayLoadoutCommit
{
Items = [ new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 0 ,
Y = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = ore . ItemKey ,
Quantity = 5 ,
Quality = 0.75 ,
Temperature = 333
}
} ]
} ] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "trade-sale-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.1" ,
Credits = 100 ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ station , ship ] } ]
} ;
var sale = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . TradeSale ,
"pilot" ,
"trade-sale-smoke" ,
1 ,
run . CurrentEntityKey ) ;
sale . TradeSale . ItemKey = ore . ItemKey ;
sale . TradeSale . Quantity = 3 ;
sale . TradeSale . SourceCargoIndex = 0 ;
sale . TradeSale . SourceX = 0 ;
sale . TradeSale . SourceY = 0 ;
var unitPrice = AetheriaRuntimeDaemonTradeItemQueries . TradeItemValue (
ore ,
ship . CargoContents [ 0 ] . Items [ 0 ] . Item ,
catalog . TradeValueSettings ) . Price ;
var result = AetheriaRuntimeDaemonOperations . Execute (
run ,
[sale] ,
new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ) ;
Require ( result . AppliedCommandIds . Contains ( sale . CommandId ) ,
"valid docked sale must commit through the daemon economy transaction" ) ;
RequireEqual ( 100 + unitPrice * 3 , run . Credits ,
"sale payout must be derived from the authoritative source instance and catalog" ) ;
RequireEqual ( 2 , CargoQuantity ( ship , ore . ItemKey ) ,
"sale must remove exactly the accepted quantity from seller cargo" ) ;
RequireEqual ( 11 , CargoQuantity ( station , ore . ItemKey ) ,
"station stock must receive the exact sold quantity" ) ;
RequireEqual ( 10 , station . CargoContents [ 0 ] . Items [ 0 ] . Item . Quantity ,
"station stock must fill the first compatible stack before allocating a new cell" ) ;
var allocated = station . CargoContents [ 0 ] . Items . Single ( slot = > slot . X = = 1 & & slot . Y = = 0 ) ;
RequireEqual ( 1 , allocated . Item . Quantity ,
"station stock overflow must use the first free authored cargo cell" ) ;
RequireNear ( 0.75 , allocated . Item . Quality , 0.000001 ,
"sale placement must preserve source instance quality" ) ;
RequireNear ( 333 , allocated . Item . Temperature , 0.000001 ,
"sale placement must preserve source instance temperature" ) ;
station . CargoContents [ 0 ] . Items [ 1 ] . Item . Quantity = 10 ;
var rejectedSale = AetheriaRuntimeDaemonCommandDocument . Create (
AetheriaRuntimeDaemonCommandKinds . TradeSale ,
"pilot" ,
"trade-sale-smoke" ,
2 ,
run . CurrentEntityKey ) ;
rejectedSale . TradeSale . ItemKey = ore . ItemKey ;
rejectedSale . TradeSale . Quantity = 1 ;
rejectedSale . TradeSale . SourceCargoIndex = 0 ;
rejectedSale . TradeSale . SourceX = 0 ;
rejectedSale . TradeSale . SourceY = 0 ;
var creditsBeforeRejection = run . Credits ;
result = AetheriaRuntimeDaemonOperations . Execute (
run ,
[rejectedSale] ,
new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ) ;
Require ( result . RejectedCommandIds . Contains ( rejectedSale . CommandId ) ,
"station stock without spatial capacity must reject the sale" ) ;
RequireEqual ( AetheriaRuntimeDaemonRejectionReasons . TradeStationNoFit ,
result . RejectedCommandReasons [ rejectedSale . CommandId ] ,
"full station stock must expose the exact trade rejection reason" ) ;
RequireEqual ( creditsBeforeRejection , run . Credits ,
"rejected sale must not credit the seller" ) ;
RequireEqual ( 2 , CargoQuantity ( ship , ore . ItemKey ) ,
"rejected sale must not remove seller cargo" ) ;
}
2026-07-15 16:36:13 +01:00
private static void StationBodiesCannotConsumePickups ( )
{
var hull = CatalogItem ( "station-filter-hull" ) ; hull . HullCapacity = PerformanceStat ( 1 ) ;
var salvage = CatalogItem ( "station-filter-salvage" ) ; salvage . Volume = 1 ;
var cargoBay = CatalogItem ( "station-filter-cargo-bay" ) ; cargoBay . InteriorOccupiedCells = 1 ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , salvage , cargoBay ] , [ ] , [ ] ) ;
var station = Entity ( 0 , 0 , "player" ) ;
station . Kind = "station" ;
station . HullItemKey = hull . ItemKey ;
2026-07-17 00:46:58 +01:00
station . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit
2026-07-15 16:36:13 +01:00
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
} ] ;
station . CargoContents = [ Cargo ( ) ] ;
var ship = Entity ( 1 , 200 , "player" ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.1" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ station , ship ] ,
DroppedPickups = [ new AetheriaRuntimeDroppedPickupCommit
{
PickupIndex = 9 ,
PositionX = 0 ,
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = salvage . ItemKey , Quantity = 1 } ,
LifetimeSeconds = 30
} ]
} ]
} ;
using var physics = NewPhysics ( ) ;
AetheriaRuntimeDaemonTickRunner . Tick (
Path . Combine ( Path . GetTempPath ( ) , "aetheria-pickup-station-filter.cc" ) ,
run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = physics ,
FrameId = 1 ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = 0.1 ,
Catalog = catalog ,
BuildPublications = false
} ) ;
RequireEqual ( 1 , run . Zones [ 0 ] . DroppedPickups . Count ,
"station world bodies must not consume ship-scoop pickups" ) ;
RequireEqual ( 0 , run . PickupContactReceipts . Count ,
"Ymir collision filtering must not publish station/pickup Begin facts" ) ;
RequireEqual ( 0 , CargoQuantity ( station , salvage . ItemKey ) ,
"station cargo must remain unchanged without a ship shield contact" ) ;
}
2026-07-11 19:11:46 +01:00
private static void PickupShieldContactCollectsOrBounces ( )
{
var hull = CatalogItem ( "contact-hull" ) ; hull . HullCapacity = PerformanceStat ( 1 ) ;
var salvage = CatalogItem ( "contact-salvage" ) ; salvage . Volume = 1 ;
2026-07-14 01:03:34 +01:00
var cargoBay = CatalogItem ( "contact-cargo-bay" ) ; cargoBay . InteriorOccupiedCells = 1 ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , salvage , cargoBay ] , [ ] , [ ] ) ;
2026-07-11 19:11:46 +01:00
AetheriaRuntimeRunCheckpointCommit Scenario ( bool full )
{
var ship = Entity ( 0 , 0 , "player" ) ; ship . HullItemKey = hull . ItemKey ;
2026-07-17 00:46:58 +01:00
ship . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit { Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 } } ] ;
2026-07-11 19:11:46 +01:00
ship . CargoContents = [ full ? Cargo ( ( salvage . ItemKey , 1 , 0 , 0 ) ) : Cargo ( ) ] ;
return new AetheriaRuntimeRunCheckpointCommit { CurrentZoneIndex = 0 , CurrentEntityKey = "zone.0.entity.0" , Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship ] , DroppedPickups = [ new AetheriaRuntimeDroppedPickupCommit { PickupIndex = 10 , PositionX = 20 , Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = salvage . ItemKey , Quantity = 1 } , LifetimeSeconds = 30 } ] } ] } ;
}
var open = Scenario ( false ) ;
2026-07-15 03:52:56 +01:00
using var openPhysics = NewPhysics ( ) ;
2026-07-11 19:11:46 +01:00
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-pickup-contact-open.cc" ) , open ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = openPhysics , FrameId = 1 , FixedDeltaSeconds = 0.1 , SimulationTimeSeconds = 0.1 , Catalog = catalog , BuildPublications = false } ) ;
2026-07-11 19:11:46 +01:00
RequireEqual ( 0 , open . Zones [ 0 ] . DroppedPickups . Count , "shield contact with capacity must collect pickup automatically" ) ;
RequireEqual ( 1 , CargoQuantity ( open . Zones [ 0 ] . Entities [ 0 ] , salvage . ItemKey ) , "contact collection must commit cargo once" ) ;
2026-07-11 19:19:47 +01:00
RequireEqual ( 1 , open . GameEvents . Count ( value = > value . Kind = = "pickup.collected" & & value . PickupIndex = = 10 ) ,
"contact collection must emit one stable event" ) ;
2026-07-14 21:38:46 +01:00
RequireEqual ( 1 , open . PickupContactReceipts . Count ,
"a real Box3D Begin fact must persist one cargo-consumption receipt" ) ;
2026-07-11 19:11:46 +01:00
var full = Scenario ( true ) ;
2026-07-15 03:52:56 +01:00
using var fullPhysics = NewPhysics ( ) ;
2026-07-11 19:11:46 +01:00
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-pickup-contact-full.cc" ) , full ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = fullPhysics , FrameId = 1 , FixedDeltaSeconds = 0.1 , SimulationTimeSeconds = 0.1 , Catalog = catalog , BuildPublications = false } ) ;
2026-07-11 19:11:46 +01:00
RequireEqual ( 1 , full . Zones [ 0 ] . DroppedPickups . Count , "full hold must leave contacted pickup alive" ) ;
Require ( full . Zones [ 0 ] . DroppedPickups [ 0 ] . VelocityX > 20 , "failed pickup must receive the fossil outward kick" ) ;
2026-07-11 19:19:47 +01:00
RequireEqual ( 1 , full . GameEvents . Count ( value = > value . Kind = = "pickup.rejected" & & value . PickupIndex = = 10 ) ,
"capacity rejection must emit one stable event" ) ;
2026-07-15 16:36:13 +01:00
var rejectionEvent = full . GameEvents . Single ( value = > value . Kind = = "pickup.rejected" & & value . PickupIndex = = 10 ) ;
RequireEqual ( "cargo-capacity" , rejectionEvent . Reason ,
"capacity rejection feedback must name the provider-owned reason" ) ;
RequireNear ( 1 , rejectionEvent . AuxiliaryValue , 0.000001 ,
"capacity rejection feedback must preserve the pre-contact cargo quantity" ) ;
2026-07-14 21:38:46 +01:00
RequireEqual ( 1 , full . PickupContactReceipts . Count ,
"capacity rejection must consume its Box3D Begin fact exactly once" ) ;
AetheriaRuntimeDaemonTickRunner . Tick ( Path . Combine ( Path . GetTempPath ( ) , "aetheria-pickup-contact-full-second.cc" ) , full ,
2026-07-14 22:25:05 +01:00
new AetheriaRuntimeDaemonTickOptions { WorldPhysics = fullPhysics , FrameId = 2 , FixedDeltaSeconds = 0.1 , SimulationTimeSeconds = 0.2 , Catalog = catalog , BuildPublications = false } ) ;
2026-07-14 21:38:46 +01:00
RequireEqual ( 1 , full . PickupContactReceipts . Count ,
"persistent or separating contact must not replay an already consumed Begin fact" ) ;
RequireEqual ( 1 , full . GameEvents . Count ( value = > value . Kind = = "pickup.rejected" & & value . PickupIndex = = 10 ) ,
"a consumed rejection fact must not emit a second gameplay event" ) ;
2026-07-11 19:19:47 +01:00
var feedback = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
new AetheriaRuntimeDaemonFrameDocument { FrameId = 1 , Run = full } ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "daemon" ) ) ;
2026-07-15 16:36:13 +01:00
Require ( Flatten ( feedback . Surface . Root ) . Any ( node = > node . Kind = = "feedback.event" & &
node . Props [ "eventKind" ] = = "pickup.rejected" & & node . Props [ "pickupIndex" ] = = "10" & &
node . Props [ "reason" ] = = "cargo-capacity" & &
node . Props [ "cargoQuantityBefore" ] = = "1" & & node . Props [ "cargoQuantityAfter" ] = = "1" ) ,
2026-07-11 19:19:47 +01:00
"Eve surface must project authoritative pickup feedback chronology" ) ;
2026-07-11 19:11:46 +01:00
}
2026-07-11 17:43:48 +01:00
private static ( AetheriaRuntimeRunCheckpointCommit Run , AetheriaRuntimeZoneSnapshotCommit Zone , AetheriaRuntimeEntitySnapshotCommit Target ) Scenario ( )
2026-07-09 19:46:41 +01:00
{
2026-07-11 19:02:42 +01:00
var source = Entity ( 1 , - 100 , "player" ) ;
var target = Entity ( 2 , 30 , "enemy" ) ;
2026-07-11 17:43:48 +01:00
var zone = new AetheriaRuntimeZoneSnapshotCommit
2026-07-09 19:46:41 +01:00
{
2026-07-11 17:43:48 +01:00
ZoneIndex = 0 ,
Entities = [ source , target ] ,
2026-07-12 01:05:25 +01:00
PhysicalPayloads =
2026-07-09 19:46:41 +01:00
[
2026-07-12 01:05:25 +01:00
new AetheriaRuntimePhysicalPayloadCommit
2026-07-09 19:46:41 +01:00
{
2026-07-12 01:05:25 +01:00
PayloadId = "smoke-projectile" ,
2026-07-11 17:43:48 +01:00
SourceEntityIndex = 1 ,
TargetEntityIndex = 2 ,
PositionX = 0 ,
PositionZ = 0 ,
VelocityX = 100 ,
VelocityY = 0 ,
Radius = 1 ,
2026-07-12 01:05:25 +01:00
ContactMagnitude = 12 ,
2026-07-11 17:43:48 +01:00
LifetimeSeconds = 5 ,
Active = true
2026-07-09 19:46:41 +01:00
}
]
} ;
2026-07-11 17:43:48 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
2026-07-09 19:46:41 +01:00
{
2026-07-11 17:43:48 +01:00
RunId = "ymir-projectile-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.1" ,
Zones = [ zone ]
2026-07-09 19:46:41 +01:00
} ;
2026-07-11 17:43:48 +01:00
return ( run , zone , target ) ;
2026-07-09 19:46:41 +01:00
}
2026-07-11 17:43:48 +01:00
private static AetheriaRuntimeEntitySnapshotCommit Entity ( int index , double x , string faction ) = > new ( )
2026-07-09 19:46:41 +01:00
{
2026-07-11 17:43:48 +01:00
EntityIndex = index ,
2026-07-14 21:38:46 +01:00
EntityId = $"smoke.entity.{index}" ,
2026-07-11 17:43:48 +01:00
Kind = "ship" ,
FactionKey = faction ,
PositionX = x ,
PositionZ = 0 ,
TargetEntityIndex = - 1 ,
IsActive = true ,
StatGrids = [ Grid ( "hull" , 100 ) , Grid ( "shield" , 0 ) , Grid ( "heat" , 0 ) ]
} ;
private static AetheriaRuntimeEntityStatGridCommit Grid ( string name , double value ) = > new ( )
2026-07-09 19:46:41 +01:00
{
2026-07-11 17:43:48 +01:00
Name = name ,
Width = 1 ,
Height = 1 ,
Values = [ value ]
} ;
2026-07-11 17:50:26 +01:00
private static AetheriaRuntimeEntityStatGridCommit Grid ( string name , int width , int height , params double [ ] values ) = > new ( )
{
Name = name ,
Width = width ,
Height = height ,
Values = values
} ;
private static double GridValue ( AetheriaRuntimeEntitySnapshotCommit entity , string name , int index ) = >
entity . StatGrids . Single ( grid = > string . Equals ( grid . Name , name , StringComparison . OrdinalIgnoreCase ) ) . Values [ index ] ;
2026-07-11 18:05:19 +01:00
private static IEnumerable < AetheriaRuntimeSurfaceComponent > Flatten ( AetheriaRuntimeSurfaceComponent root )
{
yield return root ;
foreach ( var child in root . Children )
foreach ( var descendant in Flatten ( child ) )
yield return descendant ;
}
2026-07-11 17:43:48 +01:00
private static double Stat ( AetheriaRuntimeEntitySnapshotCommit entity , string name ) = >
entity . StatGrids . Single ( grid = > string . Equals ( grid . Name , name , StringComparison . OrdinalIgnoreCase ) ) . Values [ 0 ] ;
2026-07-09 19:46:41 +01:00
private static void RequireEqual < T > ( T expected , T actual , string message )
{
if ( ! EqualityComparer < T > . Default . Equals ( expected , actual ) )
throw new InvalidOperationException ( $"{message}. Expected {expected}; actual {actual}." ) ;
}
2026-07-11 17:50:26 +01:00
private static void Require ( bool condition , string message )
{
if ( ! condition )
throw new InvalidOperationException ( message ) ;
}
private static void RequireNear ( double expected , double actual , double tolerance , string message )
{
if ( Math . Abs ( expected - actual ) > tolerance )
throw new InvalidOperationException ( $"{message}. Expected {expected}; actual {actual}." ) ;
}
2026-07-14 01:03:34 +01:00
2026-07-17 05:53:02 +01:00
private static void CultCacheRestartPreservesLoadoutAndBehaviorState ( )
{
var root = Path . Combine ( Path . GetTempPath ( ) , "aetheria-loadout-restart-" + Guid . NewGuid ( ) . ToString ( "N" ) ) ;
Directory . CreateDirectory ( root ) ;
var statePath = Path . Combine ( root , "world.cc" ) ;
try
{
var controller = CatalogItem ( "reconnect-controller" ,
new AetheriaRuntimeBehaviorPayload ( 0 , "Thermotoggle" , 0 ,
[
new AetheriaRuntimeBehaviorField ( 1 , Number ( 300 ) ) ,
new AetheriaRuntimeBehaviorField ( 2 , BoolValue ( false ) ) ,
new AetheriaRuntimeBehaviorField ( 3 , BoolValue ( true ) )
] ) ) ;
controller . Name = "Reconnect Controller" ;
2026-07-17 06:04:48 +01:00
var hull = HullCatalogItem ( "reconnect-hull" , 9 , 7 , 100 ) ;
var cargoBay = CatalogItem ( "reconnect-cargo-bay" ) ;
cargoBay . InteriorShapeWidth = 6 ;
cargoBay . InteriorShapeHeight = 4 ;
var addedModule = CatalogItem ( "reconnect-added-module" ) ;
addedModule . ShapeWidth = 1 ;
addedModule . ShapeHeight = 1 ;
addedModule . OccupiedCells = 1 ;
addedModule . ShapeCells = [ new AetheriaRuntimeShapeCell ( 0 , 0 ) ] ;
addedModule . HardpointType = "" ;
var catalog = new AetheriaRuntimeCatalogSnapshot (
[hull, cargoBay, controller, addedModule] , [ ] , [ ] ) ;
2026-07-17 05:53:02 +01:00
var ship = Entity ( 0 , 0 , "player" ) ;
2026-07-17 06:04:48 +01:00
ship . HullItemKey = hull . ItemKey ;
2026-07-17 05:53:02 +01:00
ship . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
X = 3 ,
Y = 4 ,
Rotation = "CounterClockwise" ,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = controller . ItemKey ,
Quality = 0.73 ,
Durability = 0.61 ,
Quantity = 1 ,
Enabled = true ,
OverrideShutdown = true ,
Temperature = 417
}
}
] ;
ship . CargoBays =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{
2026-07-17 06:04:48 +01:00
ItemKey = cargoBay . ItemKey ,
2026-07-17 05:53:02 +01:00
Quantity = 1 ,
Quality = 1 ,
Durability = 1 ,
Enabled = true
}
}
] ;
ship . CargoContents = [ Cargo ( ( "reconnect-salvage" , 7 , 2 , 1 ) ) ] ;
ship . WeaponGroups = [ new [ ] { 0 } ] ;
ship . ActiveWeaponGroups = [ true ] ;
ship . EquipmentStates =
[
new AetheriaRuntimeEquipmentStateCommit
{
EquipmentIndex = 0 ,
Temperature = 417 ,
PreviousTemperature = 410 ,
ThermalPerformance = 0.8 ,
DurabilityPerformance = 0.61 ,
Wear = 0.12 ,
ThermalOnline = true ,
DurabilityOnline = true ,
Online = true
}
] ;
ship . BehaviorStates =
[
new AetheriaRuntimeBehaviorStateCommit
{
OwnerKind = AetheriaRuntimeBehaviorStateProjector . EquipmentOwnerKind ,
OwnerIndex = 0 ,
BehaviorIndex = 0 ,
BehaviorKind = "Thermotoggle" ,
ThermotoggleTargetTemperature = 412 ,
ChainReached = true ,
ChainSucceeded = true ,
ChainCompleted = true
}
] ;
ship . WeaponStates =
[
new AetheriaRuntimeWeaponStateCommit
{
OwnerKind = "equipment" ,
OwnerIndex = 0 ,
BehaviorIndex = 1 ,
BehaviorKind = AetheriaRuntimeBehaviorKinds . InstantWeapon ,
Ammo = 9 ,
CooldownProgress = 0.37 ,
LockProgress = 0.82 ,
LockTargetEntityIndex = 4 ,
ShotSequence = 23
}
] ;
ship . ActiveConsumables =
[
new AetheriaRuntimeActiveConsumableCommit
{
EffectId = "effect:reconnect-tonic:1" ,
ItemKey = "reconnect-tonic" ,
Quality = 0.67 ,
Duration = 30 ,
RemainingDuration = 12 ,
BehaviorStates =
[
new AetheriaRuntimeConsumableBehaviorStateCommit
{
BehaviorId = "tonic-modifier" ,
BehaviorIndex = 0 ,
BehaviorKind = AetheriaRuntimeBehaviorKinds . StatModifier ,
ScalarState = 0.42 ,
StatModifierApplied = true ,
StatModifierExecuted = true ,
StatModifierTargetStatCount = 3
}
]
}
] ;
ship . LoadoutGeneration = new AetheriaRuntimeLoadoutGenerationReceiptCommit
{
Seed = 0xA37E ,
SourceZoneIndex = 2 ,
AvailabilityFactionKey = "player" ,
PriceExponent = 0.25 ,
Selections =
[
new AetheriaRuntimeLoadoutGenerationSelectionCommit
{
Role = "controller" ,
ItemKey = controller . ItemKey ,
ManufacturerKey = "player" ,
Price = 1200 ,
ManufacturerDistance = 1 ,
Allegiance = 0.9
}
]
} ;
2026-07-17 06:04:48 +01:00
var station = Entity ( 1 , 0 , "player" ) ;
station . Kind = "station" ;
station . DockingBayAssignments = [ ship . EntityIndex ] ;
station . CargoBays =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemKey = cargoBay . ItemKey ,
Quantity = 1 ,
Quality = 1 ,
Durability = 1 ,
Enabled = true
}
}
] ;
station . CargoContents =
[
Cargo ( ( addedModule . ItemKey , 1 , 0 , 0 ) )
] ;
2026-07-17 05:53:02 +01:00
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "loadout-restart-smoke" ,
CurrentZoneIndex = 0 ,
2026-07-17 06:04:48 +01:00
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ ship , station ] } ]
2026-07-17 05:53:02 +01:00
} ;
run . CurrentEntityKey = run . EntityRecordKey ( 0 , ship . EntityIndex ) ;
var frame = AetheriaRuntimeDaemonFrameDocument . Create (
run , "smoke" , "loadout-restart" , 41 , 4.1 , 0.1 ) ;
2026-07-17 06:04:48 +01:00
var shipKey = run . EntityRecordKey ( 0 , ship . EntityIndex ) ;
var stationKey = run . EntityRecordKey ( 0 , station . EntityIndex ) ;
var surface = AetheriaRuntimeDaemonGameSurfaceBuilder . Build (
frame ,
new AetheriaRuntimeDaemonHealthDocument ( ) ,
AetheriaRuntimeDaemonCommandBoundaryDocument . Create ( "smoke" ) ,
catalog : catalog ) ;
var equipOperation = AetheriaRuntimeDaemonSurfaceCommandCatalog . CommandName (
AetheriaRuntimeDaemonCommandKinds . EquipItem ) ;
Require ( surface . Commands . Any ( command = > command . Command = = equipOperation ) ,
"docked Eve surface must advertise the generic equip operation before reconnect" ) ;
var request = new EveSurfaceCommandRequest (
"aetheria" ,
AetheriaRuntimeDaemonGameSurfaceBuilder . PilotSurfaceId ,
CultMesh . OperationInvocation ( equipOperation ) ,
CultMesh . OperationPayload (
( "entityId" , shipKey ) ,
( "sourceKind" , AetheriaRuntimeRefitSourceKinds . Cargo ) ,
( "originEntityKey" , stationKey ) ,
( "originIndex" , "0" ) ,
( "destinationEntityKey" , shipKey ) ,
( "itemKey" , addedModule . ItemKey ) ,
( "sourceX" , "0" ) ,
( "sourceY" , "0" ) ,
( "destinationX" , "5" ) ,
( "destinationY" , "2" ) ,
( "hasDestinationPosition" , "true" ) ) ,
DateTimeOffset . UtcNow ,
"loadout-restart-smoke" ) ;
Require ( AetheriaRuntimeDaemonOperationsClient . TryCreateSurfaceCommandDocument (
request ,
frame ,
"." ,
"loadout-restart-smoke" ,
"refit" ,
out var equipCommand ) & & equipCommand ! = null ,
"generic Eve equip request must translate into a typed daemon command" ) ;
var refit = AetheriaRuntimeDaemonOperations . Execute (
run ,
[equipCommand!] ,
new AetheriaRuntimeDaemonOperationContext { Catalog = catalog } ) ;
Require ( refit . AppliedCommandIds . Contains ( equipCommand ! . CommandId , StringComparer . Ordinal ) ,
"generic Eve equip command must commit through the atomic daemon refit transaction: " +
string . Join ( "," , refit . RejectedCommandReasons . Values ) ) ;
Require ( ship . Equipment . Any ( slot = > slot . Item . ItemKey = = addedModule . ItemKey & &
slot . X = = 5 & & slot . Y = = 2 ) ,
"accepted generic refit must place the exact module in daemon world truth" ) ;
RequireEqual ( 0 , station . CargoContents . Single ( ) . Items . Count ,
"accepted generic refit must remove the exact source item atomically" ) ;
2026-07-17 05:53:02 +01:00
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > (
AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReplaceAsync ( frame ) . GetAwaiter ( ) . GetResult ( ) ;
node . FlushAsync ( soft : false ) . GetAwaiter ( ) . GetResult ( ) ;
}
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
var durable = node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > (
AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReadAsync ( ) . GetAwaiter ( ) . GetResult ( )
? ? throw new InvalidOperationException ( "Durable loadout restart frame is missing." ) ;
2026-07-17 06:04:48 +01:00
var restored = durable . Run . Zones . Single ( ) . Entities . Single ( entity = > entity . EntityIndex = = ship . EntityIndex ) ;
var restoredStation = durable . Run . Zones . Single ( ) . Entities . Single ( entity = > entity . EntityIndex = = station . EntityIndex ) ;
var installed = restored . Equipment . Single ( slot = > slot . Item . ItemKey = = controller . ItemKey ) ;
2026-07-17 05:53:02 +01:00
RequireEqual ( "reconnect-hull" , restored . HullItemKey ,
"CultCache restart must preserve daemon-owned hull identity" ) ;
Require ( installed . X = = 3 & & installed . Y = = 4 & & installed . Rotation = = "CounterClockwise" ,
"CultCache restart must preserve exact equipment placement and rotation" ) ;
RequireNear ( 0.73 , installed . Item . Quality , 0.000001 ,
"CultCache restart must preserve installed item quality" ) ;
RequireNear ( 0.61 , installed . Item . Durability , 0.000001 ,
"CultCache restart must preserve installed item durability" ) ;
Require ( installed . Item . OverrideShutdown & & installed . Item . Temperature = = 417 ,
"CultCache restart must preserve per-instance thermal controls" ) ;
RequireEqual ( 7 , restored . CargoContents . Single ( ) . Items . Single ( ) . Item . Quantity ,
"CultCache restart must preserve cargo stack quantity" ) ;
Require ( restored . WeaponGroups . Single ( ) . SequenceEqual ( new [ ] { 0 } ) & &
restored . ActiveWeaponGroups . SequenceEqual ( new [ ] { true } ) ,
"CultCache restart must preserve weapon membership and held state" ) ;
RequireNear ( 0.12 , restored . EquipmentStates . Single ( ) . Wear , 0.000001 ,
"CultCache restart must preserve equipment wear state" ) ;
RequireNear ( 412 , restored . BehaviorStates . Single ( ) . ThermotoggleTargetTemperature , 0.000001 ,
"CultCache restart must preserve executable behavior state" ) ;
Require ( restored . BehaviorStates . Single ( ) . ChainCompleted ,
"CultCache restart must preserve specialized chain chronology" ) ;
Require ( restored . WeaponStates . Single ( ) . ShotSequence = = 23 & &
restored . WeaponStates . Single ( ) . Ammo = = 9 ,
"CultCache restart must preserve weapon chronology and ammunition" ) ;
var consumableState = restored . ActiveConsumables . Single ( ) . BehaviorStates . Single ( ) ;
Require ( consumableState . StatModifierApplied & & consumableState . StatModifierExecuted & &
consumableState . StatModifierTargetStatCount = = 3 ,
"CultCache restart must preserve active consumable execution state" ) ;
Require ( restored . LoadoutGeneration ? . Selections . Single ( ) . ItemKey = = controller . ItemKey ,
"CultCache restart must preserve generated-loadout provenance" ) ;
2026-07-17 06:04:48 +01:00
Require ( restored . Equipment . Any ( slot = > slot . Item . ItemKey = = addedModule . ItemKey & &
slot . X = = 5 & & slot . Y = = 2 ) ,
"CultCache restart must preserve the generic Eve refit's accepted placement" ) ;
RequireEqual ( 0 , restoredStation . CargoContents . Single ( ) . Items . Count ,
"CultCache restart must not resurrect the generic refit's consumed source item" ) ;
2026-07-17 05:53:02 +01:00
var capability = AetheriaRuntimeInputCapabilityDocument . FromFrame (
durable , catalog : catalog ) ;
RequireEqual ( "1" , capability . Actions . Single ( action = >
action . ActionId = = "weapon-group.0.fire" ) . Payload [ "currentValue" ] ,
"generic Eve reconnect must observe the daemon-owned held weapon state" ) ;
RequireNear ( 412 , capability . Actions . Single ( action = >
action . ActionId = = "equipment.0.behavior.0" ) . InputValue ? . CurrentValue ? ? double . NaN ,
0.000001 ,
"generic Eve reconnect must observe the daemon-owned thermostat target" ) ;
}
}
finally
{
if ( Directory . Exists ( root ) )
Directory . Delete ( root , recursive : true ) ;
}
}
2026-07-15 08:27:36 +01:00
private static void YmirRestartDoesNotReplayConsumedPickupContact ( )
{
var root = Path . Combine ( Path . GetTempPath ( ) , "aetheria-ymir-restart-" + Guid . NewGuid ( ) . ToString ( "N" ) ) ;
Directory . CreateDirectory ( root ) ;
var statePath = Path . Combine ( root , "world.cc" ) ;
try
{
var hull = CatalogItem ( "restart-contact-hull" ) ; hull . HullCapacity = PerformanceStat ( 1 ) ;
var salvage = CatalogItem ( "restart-contact-salvage" ) ; salvage . Volume = 1 ;
var cargoBay = CatalogItem ( "restart-contact-cargo-bay" ) ; cargoBay . InteriorOccupiedCells = 1 ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ hull , salvage , cargoBay ] , [ ] , [ ] ) ;
var ship = Entity ( 0 , 0 , "player" ) ; ship . HullItemKey = hull . ItemKey ;
2026-07-17 00:46:58 +01:00
ship . CargoBays = [ new AetheriaRuntimeLoadoutItemSlotCommit
2026-07-15 08:27:36 +01:00
{
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = cargoBay . ItemKey , Quantity = 1 }
} ] ;
ship . CargoContents = [ Cargo ( ( salvage . ItemKey , 1 , 0 , 0 ) ) ] ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "ymir-restart-contact-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit
{
ZoneIndex = 0 ,
Entities = [ ship ] ,
DroppedPickups = [ new AetheriaRuntimeDroppedPickupCommit
{
PickupIndex = 10 ,
PositionX = 20 ,
Item = new AetheriaRuntimeLoadoutItemCommit { ItemKey = salvage . ItemKey , Quantity = 1 } ,
LifetimeSeconds = 30
} ]
} ]
} ;
var frame = new AetheriaRuntimeDaemonFrameDocument
{
FrameId = 1 ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = 0.1 ,
Run = run
} ;
using ( var physics = new AetheriaYmirWorldPhysics ( ) )
{
AetheriaRuntimeDaemonTickRunner . Tick ( statePath , run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = physics ,
FrameId = 1 ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = 0.1 ,
Catalog = catalog ,
BuildPublications = false
} ) ;
RequireEqual ( 1 , run . PickupContactReceipts . Count ,
"pre-restart rejection must consume exactly one Box3D Begin fact" ) ;
var rejectedVelocity = run . Zones [ 0 ] . DroppedPickups . Single ( ) . VelocityX ;
Require ( rejectedVelocity > 20 , "pre-restart rejection must persist the outward kick in world truth" ) ;
frame . Run = run ;
using var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) ;
using var persistence = AetheriaYmirPersistenceCoordinator . OpenAsync ( node , physics , null )
. GetAwaiter ( ) . GetResult ( ) ;
var capture = persistence . Capture ( frame ) ;
persistence . PersistPrivateAsync ( capture ) . GetAwaiter ( ) . GetResult ( ) ;
node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > ( AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReplaceAsync ( frame ) . GetAwaiter ( ) . GetResult ( ) ;
node . FlushAsync ( soft : false ) . GetAwaiter ( ) . GetResult ( ) ;
persistence . ActivateAsync ( ) . GetAwaiter ( ) . GetResult ( ) ;
Require ( ! AetheriaDocumentRegistry . DocumentTypes . Contains ( typeof ( AetheriaYmirResumeDocument ) ) ,
"daemon-private Ymir resume types must not enter the public Aetheria registry" ) ;
Require ( ! node . Cache . AllEntries . Any ( value = > value is AetheriaYmirResumeDocument or AetheriaYmirJournalChunkDocument ) ,
"public CultMesh cache must not enumerate daemon-private Ymir restart material" ) ;
}
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
var durable = node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > ( AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReadAsync ( ) . GetAwaiter ( ) . GetResult ( )
? ? throw new InvalidOperationException ( "Durable restart smoke frame is missing." ) ;
using var restoredPhysics = new AetheriaYmirWorldPhysics ( ) ;
using var persistence = AetheriaYmirPersistenceCoordinator . OpenAsync ( node , restoredPhysics , durable )
. GetAwaiter ( ) . GetResult ( ) ;
AetheriaRuntimeDaemonTickRunner . Tick ( statePath , durable . Run ,
new AetheriaRuntimeDaemonTickOptions
{
WorldPhysics = restoredPhysics ,
FrameId = 2 ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = 0.2 ,
Catalog = catalog ,
BuildPublications = false
} ) ;
RequireEqual ( 1 , durable . Run . PickupContactReceipts . Count ,
"restart must not replay an already consumed Box3D Begin fact" ) ;
RequireEqual ( 1 , durable . Run . GameEvents . Count ( value = >
value . Kind = = "pickup.rejected" & & value . PickupIndex = = 10 ) ,
"restart must not duplicate authoritative pickup rejection feedback" ) ;
}
}
finally
{
if ( Directory . Exists ( root ) )
Directory . Delete ( root , recursive : true ) ;
}
}
2026-07-16 22:32:40 +01:00
private static void CombatLockSurvivesPublicFrameRestart ( )
{
var root = Path . Combine ( Path . GetTempPath ( ) , "aetheria-combat-restart-" + Guid . NewGuid ( ) . ToString ( "N" ) ) ;
Directory . CreateDirectory ( root ) ;
var statePath = Path . Combine ( root , "world.cc" ) ;
try
{
var source = Entity ( 0 , 0 , "player" ) ;
source . DirectionX = 1 ;
source . TargetEntityIndex = 1 ;
source . Contacts =
[
new AetheriaRuntimeEntityContactCommit
{ TargetEntityIndex = 1 , InfoGathered = 1 , Hostile = true , Visible = true }
] ;
source . WeaponGroups = [ new [ ] { 0 } ] ;
source . Equipment =
[
new AetheriaRuntimeLoadoutItemSlotCommit
{
Item = new AetheriaRuntimeLoadoutItemCommit
{ ItemKey = "restart-instant" , Quality = 1 , Durability = 1 , Enabled = true }
}
] ;
var target = Entity ( 1 , 80 , "raider" ) ;
var run = new AetheriaRuntimeRunCheckpointCommit
{
RunId = "combat-restart-smoke" ,
CurrentZoneIndex = 0 ,
CurrentEntityKey = "zone.0.entity.0" ,
Zones = [ new AetheriaRuntimeZoneSnapshotCommit { ZoneIndex = 0 , Entities = [ source , target ] } ]
} ;
var payload = new AetheriaRuntimeBehaviorPayload ( 0 , AetheriaRuntimeBehaviorKinds . InstantWeapon , 0 ,
[
new AetheriaRuntimeBehaviorField ( 2 , PerformanceStat ( 20 ) ) ,
new AetheriaRuntimeBehaviorField ( 6 , PerformanceStat ( 150 ) ) ,
new AetheriaRuntimeBehaviorField ( 15 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 16 , PerformanceStat ( 200 ) ) ,
new AetheriaRuntimeBehaviorField ( 17 , PerformanceStat ( 1 ) ) ,
new AetheriaRuntimeBehaviorField ( 19 , PerformanceStat ( 0.5 ) ) ,
new AetheriaRuntimeBehaviorField ( 23 , PerformanceStat ( 45 ) ) ,
new AetheriaRuntimeBehaviorField ( 24 , PerformanceStat ( 0 ) ) ,
new AetheriaRuntimeBehaviorField ( 25 , PerformanceStat ( 1 ) )
] ) ;
var catalog = new AetheriaRuntimeCatalogSnapshot ( [ CatalogItem ( "restart-instant" , payload ) ] , [ ] , [ ] ) ;
var fire = new AetheriaRuntimeDaemonIntentState ( ) ;
fire . WeaponGroups . Add ( new AetheriaRuntimeDaemonWeaponGroupIntent
{
ActorEntityKey = "zone.0.entity.0" , WeaponGroup = 0 , Fire = true , Active = true
} ) ;
using ( var physics = new AetheriaYmirWorldPhysics ( ) )
AetheriaRuntimeDaemonSimulation . Step ( run , fire , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
physics , catalog , 1 , 0.1 ) ;
var state = source . WeaponStates . Single ( value = >
value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . InstantWeapon ) ;
Require ( state . TriggerPending & & state . LockProgress > 0 & & state . LockProgress < 0.99 & &
run . ShotReceipts . Count = = 0 ,
"combat restart fixture must stop with one pending trigger and a partial daemon lock" ) ;
var partialProgress = state . LockProgress ;
var frame = new AetheriaRuntimeDaemonFrameDocument
{
FrameId = 1 ,
FixedDeltaSeconds = 0.1 ,
SimulationTimeSeconds = 0.1 ,
Run = run
} ;
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > ( AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReplaceAsync ( frame ) . GetAwaiter ( ) . GetResult ( ) ;
node . FlushAsync ( soft : false ) . GetAwaiter ( ) . GetResult ( ) ;
}
using ( var node = AetheriaStateNode . OpenAsync ( statePath ) . GetAwaiter ( ) . GetResult ( ) )
{
var durable = node . MutableDocument < AetheriaRuntimeDaemonFrameDocument > ( AetheriaRuntimeVerseRecordKeys . DaemonFrameLatest )
. ReadAsync ( ) . GetAwaiter ( ) . GetResult ( )
? ? throw new InvalidOperationException ( "Durable combat restart frame is missing." ) ;
var restoredSource = durable . Run . Zones [ 0 ] . Entities [ 0 ] ;
var restoredState = restoredSource . WeaponStates . Single ( value = >
value . BehaviorKind = = AetheriaRuntimeBehaviorKinds . InstantWeapon ) ;
Require ( restoredState . TriggerPending & & Math . Abs ( restoredState . LockProgress - partialProgress ) < 0.000001 ,
"public frame restart must retain the pending trigger and exact partial lock progress" ) ;
using var restoredPhysics = new AetheriaYmirWorldPhysics ( ) ;
for ( var frameId = 2 ; frameId < 12 & & durable . Run . ShotReceipts . Count = = 0 ; frameId + + )
AetheriaRuntimeDaemonSimulation . Step ( durable . Run , new AetheriaRuntimeDaemonIntentState ( ) , 0.1 ,
AetheriaRuntimeDaemonSimulationSettings . AetheriaDefault ,
restoredPhysics , catalog , frameId , frameId * 0.1 ) ;
RequireEqual ( 1 , durable . Run . ShotReceipts . Count ,
"restart must complete one pending instant-weapon shot, not lose or duplicate it" ) ;
RequireEqual ( 1 , durable . Run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.started" ) ,
"restart must not replay the pre-restart lock-start transition" ) ;
RequireEqual ( 1 , durable . Run . GameEvents . Count ( value = > value . Kind = = "weapon.lock.acquired" ) ,
"restart must publish one completed lock transition" ) ;
RequireEqual ( 1 , durable . Run . GameEvents . Count ( value = > value . Kind = = "shot.committed" ) ,
"restart must publish one committed-shot transition" ) ;
}
}
finally
{
if ( Directory . Exists ( root ) )
Directory . Delete ( root , recursive : true ) ;
}
}
2026-07-14 21:38:46 +01:00
private sealed class ScriptedWorldPhysics ( params AetheriaRuntimeWorldBeginContact [ ] contacts ) : IAetheriaRuntimeWorldPhysics
2026-07-14 01:03:34 +01:00
{
public string ImplementationId = > "smoke.scripted-world" ;
2026-07-14 21:38:46 +01:00
public void RetainWorlds ( string runId , IReadOnlyList < int > zoneIndices ) { }
public AetheriaRuntimeWorldPickupStep ApplyPickupRejection (
string runId ,
int zoneIndex ,
AetheriaRuntimeWorldBeginContact contact ) = >
new ( ) { PickupIndex = contact . PickupIndex , VelocityX = contact . NormalX * 25 , VelocityZ = contact . NormalZ * 25 } ;
2026-07-14 01:03:34 +01:00
public AetheriaRuntimeWorldStep Step (
2026-07-14 21:38:46 +01:00
string runId ,
long frameId ,
int simulationStepIndex ,
2026-07-14 01:03:34 +01:00
AetheriaRuntimeZoneSnapshotCommit zone ,
IReadOnlyList < AetheriaRuntimeEntitySnapshotCommit > entities ,
double deltaSeconds ) = > new ( [ ] , [ ] , contacts ) ;
2026-07-14 22:25:05 +01:00
public AetheriaRuntimePhysicalPayloadStep StepPhysicalPayloads (
string runId ,
long frameId ,
int simulationStepIndex ,
AetheriaRuntimeZoneSnapshotCommit zone ,
IReadOnlyList < AetheriaRuntimeEntitySnapshotCommit > entities ,
double deltaSeconds ) = > new ( zone . PhysicalPayloads , [ ] ) ;
2026-07-14 01:03:34 +01:00
}
2026-07-09 19:46:41 +01:00
}