Sample renderer animation from daemon time

This commit is contained in:
Meta Vens 2026-06-21 16:18:20 +01:00
commit e48c357efa
9 changed files with 57 additions and 8 deletions

View file

@ -1863,7 +1863,8 @@ static void RequireDaemonRenderQueryAuthority(string root)
"public double GravityTerrainDepth",
"public double GravityTerrainDepthExponent",
"public double GravityTerrainBoundaryFog",
"public double GravityTerrainWaveFrequency"
"public double GravityTerrainWaveFrequency",
"public double SimulationTimeSeconds"
};
var missingPackageSnapshotSymbols = requiredSnapshotSymbols
@ -1915,6 +1916,13 @@ static void RequireDaemonRenderQueryAuthority(string root)
"ZoneRenderer must position bodies from daemon render body poses instead of the mirrored Unity Zone orbit evaluator.");
}
if (zoneRenderer.Contains("Zone.Time", StringComparison.Ordinal) ||
zoneRenderer.Contains("Zone?.Time", StringComparison.Ordinal))
{
throw new InvalidOperationException(
"ZoneRenderer must sample animation and terrain from daemon simulation time instead of mirrored Unity Zone time.");
}
if (zoneRenderer.Contains("Zone.PlanetInstances[planet.Key]", StringComparison.Ordinal))
{
throw new InvalidOperationException(
@ -1995,6 +2003,7 @@ static void RequireDaemonRenderQueryAuthority(string root)
"AetheriaRuntimeDaemonRenderQueries.QueryCompassMarkers(",
"AetheriaRuntimeDaemonRenderQueries.QueryVisibleEntityIndices(",
"AetheriaRuntimeDaemonRenderQueries.QueryWormholeExits(",
"private double DaemonSimulationTimeSeconds => _daemonZoneSnapshot?.SimulationTimeSeconds ?? 0;",
"_daemonCompassMarkersByEntityIndex.TryGetValue(entityInstance.Entity.DaemonEntityIndex, out var marker)",
"_daemonBodyPosesByBodyKey.TryGetValue(planet.Key, out var pose)",
"pose.GravityWaveSpeed"

View file

@ -284,6 +284,9 @@ public sealed class AetheriaZoneState
[Key(13)]
public double GravityTerrainWaveFrequency { get; set; } = 1.0;
[Key(14)]
public double SimulationTimeSeconds { get; set; }
}
[MessagePackObject]

View file

@ -2266,7 +2266,8 @@ public class ActionGameManager : MonoBehaviour
var blueprint = new ZoneConstructionBlueprint
{
Radius = 2000,
Mass = 10000
Mass = 10000,
Time = (float)zone.SimulationTimeSeconds
};
foreach (var orbit in zone.Orbits ?? Array.Empty<AetheriaRuntimeOrbitSnapshotCommit>())
@ -3462,6 +3463,7 @@ public class ActionGameManager : MonoBehaviour
return;
}
StampDaemonZoneSimulationTime(observed.Run, observed.Frame.SimulationTimeSeconds);
if (TryRestoreEntityGraphFromDaemonRun(observed.Run))
{
_lastAppliedAuthoritativeDaemonFrameId = observed.Frame.FrameId;
@ -3469,6 +3471,17 @@ public class ActionGameManager : MonoBehaviour
}
}
private static void StampDaemonZoneSimulationTime(
AetheriaRuntimeRunCheckpointCommit run,
double simulationTimeSeconds)
{
foreach (var zone in run?.Zones ?? Array.Empty<AetheriaRuntimeZoneSnapshotCommit>())
{
if (zone != null)
zone.SimulationTimeSeconds = simulationTimeSeconds;
}
}
private bool TryRequestDaemonMoveVector(Vector2 movement)
{
var observer = ResolveDaemonObserver();

View file

@ -182,6 +182,7 @@ public class DaemonRuntimeDocumentTests
Assert.AreEqual(1, run.Zones[0].Entities[0].TargetEntityIndex);
Assert.AreEqual("zone.0.entity.0", result.Intents.Movement.ActorEntityKey);
Assert.AreEqual(1.0, result.Intents.Movement.DirectionX, 0.0001);
Assert.AreEqual(12.5, result.Run.Zones[0].SimulationTimeSeconds, 0.0001);
Assert.IsTrue(AetheriaRuntimeDaemonFrameStore.TryReadFrame(statePath, out var frame));
Assert.AreEqual(result.FramePath, AetheriaRuntimeDaemonFrameStore.GetFramePath(statePath));
Assert.AreEqual("test-daemon", frame.DaemonId);
@ -199,6 +200,7 @@ public class DaemonRuntimeDocumentTests
CollectionAssert.Contains(frame.AccountedCommandIds, targetCommand.CommandId);
CollectionAssert.Contains(frame.AccountedCommandIds, movementCommand.CommandId);
Assert.AreEqual(1, frame.Run.Zones[0].Entities[0].TargetEntityIndex);
Assert.AreEqual(12.5, frame.Run.Zones[0].SimulationTimeSeconds, 0.0001);
Assert.AreEqual(
AetheriaRuntimeDaemonPublicationStore.GetProviderAdvertisementPath(statePath),
result.ProviderAdvertisementPath);

View file

@ -495,7 +495,7 @@ public class ZoneRenderer : MonoBehaviour
AetheriaRuntimeDaemonRenderQueries.QueryAsteroidInstancePoses(
_daemonZoneSnapshot,
key,
Zone?.Time ?? 0,
DaemonSimulationTimeSeconds,
_visibleAsteroidInstancePoses);
}
@ -544,7 +544,7 @@ public class ZoneRenderer : MonoBehaviour
if (planet.Value is GasGiantObject gasGiantObject)
{
gasGiantObject.GravityWaves.material.SetFloat("_Phase",
Zone.Time * (float)pose.GravityWaveSpeed);
(float)(DaemonSimulationTimeSeconds * pose.GravityWaveSpeed));
if (!string.Equals(pose.Kind, "sun", StringComparison.OrdinalIgnoreCase))
{
var parent = new float2((float)pose.ParentCenterX, (float)pose.ParentCenterZ);
@ -661,9 +661,11 @@ public class ZoneRenderer : MonoBehaviour
_daemonZoneSnapshot,
position.x,
position.y,
Zone?.Time ?? 0);
DaemonSimulationTimeSeconds);
}
private double DaemonSimulationTimeSeconds => _daemonZoneSnapshot?.SimulationTimeSeconds ?? 0;
public void DestroyLoot(ItemPickup loot)
{
_loot.Remove(loot);

View file

@ -817,7 +817,8 @@ namespace GameCult.Aetheria.State.Verse
double gravityTerrainDepth,
double gravityTerrainDepthExponent,
double gravityTerrainBoundaryFog,
double gravityTerrainWaveFrequency)
double gravityTerrainWaveFrequency,
double simulationTimeSeconds)
{
RecordKey = recordKey;
Name = name;
@ -835,6 +836,7 @@ namespace GameCult.Aetheria.State.Verse
GravityTerrainDepthExponent = gravityTerrainDepthExponent;
GravityTerrainBoundaryFog = gravityTerrainBoundaryFog;
GravityTerrainWaveFrequency = gravityTerrainWaveFrequency;
SimulationTimeSeconds = simulationTimeSeconds;
}
public string RecordKey { get; }
@ -853,6 +855,7 @@ namespace GameCult.Aetheria.State.Verse
public double GravityTerrainDepthExponent { get; }
public double GravityTerrainBoundaryFog { get; }
public double GravityTerrainWaveFrequency { get; }
public double SimulationTimeSeconds { get; }
}
public sealed class AetheriaRuntimeDroppedPickupSnapshot

View file

@ -1153,7 +1153,8 @@ namespace GameCult.Aetheria.State.Verse
var gravityTerrainDepthExponent = ReadFieldDouble(ref reader, fields, 11, 1.0);
var gravityTerrainBoundaryFog = ReadFieldDouble(ref reader, fields, 12);
var gravityTerrainWaveFrequency = ReadFieldDouble(ref reader, fields, 13, 1.0);
SkipRemaining(ref reader, fields, 14);
var simulationTimeSeconds = ReadFieldDouble(ref reader, fields, 14);
SkipRemaining(ref reader, fields, 15);
return new AetheriaRuntimeZoneStateSnapshot(
recordKey,
name,
@ -1170,7 +1171,8 @@ namespace GameCult.Aetheria.State.Verse
gravityTerrainDepth,
gravityTerrainDepthExponent,
gravityTerrainBoundaryFog,
gravityTerrainWaveFrequency);
gravityTerrainWaveFrequency,
simulationTimeSeconds);
}
private static IReadOnlyList<AetheriaRuntimeDroppedPickupSnapshot> ReadFieldDroppedPickups(ref MessagePackReader reader, int fields, int index)

View file

@ -96,6 +96,7 @@ namespace GameCult.Aetheria.State.Verse
run,
commands,
options.OperationContext);
StampZoneSimulationTime(operationResult.Run, options.SimulationTimeSeconds);
var frame = AetheriaRuntimeDaemonFrameDocument.Create(
operationResult.Run,
@ -194,5 +195,16 @@ namespace GameCult.Aetheria.State.Verse
editorTuiSurfacePath);
}
private static void StampZoneSimulationTime(
AetheriaRuntimeRunCheckpointCommit run,
double simulationTimeSeconds)
{
foreach (var zone in run?.Zones ?? Array.Empty<AetheriaRuntimeZoneSnapshotCommit>())
{
if (zone != null)
zone.SimulationTimeSeconds = simulationTimeSeconds;
}
}
}
}

View file

@ -279,6 +279,9 @@ namespace GameCult.Aetheria.State.Verse
[Key(15)]
public double GravityTerrainWaveFrequency { get; set; } = 1.0;
[Key(16)]
public double SimulationTimeSeconds { get; set; }
}
[MessagePackObject]