Prove generic celestial world lowering

This commit is contained in:
Meta Vens 2026-07-16 04:41:06 +01:00
commit 93a95b23df
4 changed files with 156 additions and 28 deletions

View file

@ -225,6 +225,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
EveUnityAimPresentationRenderer aimRenderer = null;
EveUnityBeamPresentation beamPresentation = null;
EveUnityBeamPresentationRenderer beamRenderer = null;
EveUnityShotTrajectoryRenderer trajectories = null;
try
{
@ -279,7 +280,13 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(cockpitProgressCount, Is.GreaterThanOrEqualTo(7));
Assert.That(loweredSurface.Q<VisualElement>("aetheria.daemon.game.frame").style.display.value,
Is.EqualTo(DisplayStyle.None), "Daemon diagnostics leaked into the pilot UI.");
host.ShotAvailable += shot => observedShot = shot;
trajectories = root.GetComponent<EveUnityShotTrajectoryRenderer>();
Assert.That(trajectories, Is.Not.Null);
host.ShotAvailable += shot =>
{
observedShot = shot;
maximumTrajectoryCount = Math.Max(maximumTrajectoryCount, trajectories.ActiveTrajectoryCount);
};
runtime = host.Runtime;
Assert.That(runtime, Is.Not.Null);
Assert.That(runtime.ActiveWorld.PlayerEntityId, Is.Not.Empty);
@ -507,9 +514,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(runtime.ActiveVersion, Is.GreaterThanOrEqualTo(runtime.LastReceipt.SourceVersion));
actionReceipt = WitnessReceipt.From("action", runtime.LastReceipt);
var trajectories = root.GetComponent<EveUnityShotTrajectoryRenderer>();
var combatRenderer = root.GetComponent<EveUnityCombatPresentationRenderer>();
Assert.That(trajectories, Is.Not.Null);
Assert.That(combatRenderer, Is.Not.Null);
var shotDeadline = Time.realtimeSinceStartup + 20f;
while (Time.realtimeSinceStartup < shotDeadline &&
@ -823,7 +828,10 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Convert.ToSingle(fieldViewport.GetType().GetProperty("MaxX")?.GetValue(fieldViewport)),
Convert.ToSingle(fieldViewport.GetType().GetProperty("MaxY")?.GetValue(fieldViewport)),
Convert.ToInt32(fieldSplats.GetType().GetProperty("Count")?.GetValue(fieldSplats)),
playerRendererFacts);
playerRendererFacts,
root.GetComponentsInChildren<EveUnityPlayableWorldEntityMarker>(includeInactive: true)
.Select(marker => PresentedEntityFact.From(camera, marker))
.ToArray());
}
finally
{
@ -893,7 +901,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
float fieldViewportMaxX,
float fieldViewportMaxY,
int fieldSplatCount,
RendererFact[] playerRendererFacts)
RendererFact[] playerRendererFacts,
PresentedEntityFact[] presentedEntityFacts)
{
var path = Environment.GetEnvironmentVariable("EVEUNITY_WITNESS_FACTS_PATH");
if (string.IsNullOrWhiteSpace(path)) return;
@ -961,6 +970,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
fieldViewportMaxY = fieldViewportMaxY,
fieldSplatCount = fieldSplatCount,
playerRenderers = playerRendererFacts,
presentedEntities = presentedEntityFacts,
mapChannelRendererCount = mapChannelRendererCount,
mapChangedPixels = mapChangedPixels,
pilotCameraExcludesMapChannel = pilotCameraExcludesMapChannel,
@ -1034,6 +1044,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
public float fieldViewportMaxY;
public int fieldSplatCount;
public RendererFact[] playerRenderers;
public PresentedEntityFact[] presentedEntities;
public int mapChannelRendererCount;
public int mapChangedPixels;
public bool pilotCameraExcludesMapChannel;
@ -1110,6 +1121,45 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
}
}
[Serializable]
private sealed class PresentedEntityFact
{
public string entityId;
public string entityKind;
public string label;
public string assetRef;
public string worldPosition;
public string worldScale;
public int rendererCount;
public int enabledRendererCount;
public bool intersectsPilotFrustum;
public float viewportWidth;
public float viewportHeight;
public static PresentedEntityFact From(Camera camera, EveUnityPlayableWorldEntityMarker marker)
{
var renderers = marker.GetComponentsInChildren<Renderer>(includeInactive: true);
MeasureViewportCoverage(camera, renderers, out var width, out var height);
var planes = GeometryUtility.CalculateFrustumPlanes(camera);
return new PresentedEntityFact
{
entityId = marker.EntityId,
entityKind = marker.EntityKind,
label = marker.Label,
assetRef = marker.AssetRef,
worldPosition = FormatVector(marker.transform.position),
worldScale = FormatVector(marker.transform.lossyScale),
rendererCount = renderers.Length,
enabledRendererCount = renderers.Count(renderer => renderer.enabled && renderer.gameObject.activeInHierarchy),
intersectsPilotFrustum = renderers.Any(renderer =>
renderer.enabled && renderer.gameObject.activeInHierarchy &&
GeometryUtility.TestPlanesAABB(planes, renderer.bounds)),
viewportWidth = width,
viewportHeight = height
};
}
}
[Serializable]
private sealed class MaterialFact
{

View file

@ -225,6 +225,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
EveUnityAimPresentationRenderer aimRenderer = null;
EveUnityBeamPresentation beamPresentation = null;
EveUnityBeamPresentationRenderer beamRenderer = null;
EveUnityShotTrajectoryRenderer trajectories = null;
try
{
@ -279,7 +280,13 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(cockpitProgressCount, Is.GreaterThanOrEqualTo(7));
Assert.That(loweredSurface.Q<VisualElement>("aetheria.daemon.game.frame").style.display.value,
Is.EqualTo(DisplayStyle.None), "Daemon diagnostics leaked into the pilot UI.");
host.ShotAvailable += shot => observedShot = shot;
trajectories = root.GetComponent<EveUnityShotTrajectoryRenderer>();
Assert.That(trajectories, Is.Not.Null);
host.ShotAvailable += shot =>
{
observedShot = shot;
maximumTrajectoryCount = Math.Max(maximumTrajectoryCount, trajectories.ActiveTrajectoryCount);
};
runtime = host.Runtime;
Assert.That(runtime, Is.Not.Null);
Assert.That(runtime.ActiveWorld.PlayerEntityId, Is.Not.Empty);
@ -507,9 +514,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Assert.That(runtime.ActiveVersion, Is.GreaterThanOrEqualTo(runtime.LastReceipt.SourceVersion));
actionReceipt = WitnessReceipt.From("action", runtime.LastReceipt);
var trajectories = root.GetComponent<EveUnityShotTrajectoryRenderer>();
var combatRenderer = root.GetComponent<EveUnityCombatPresentationRenderer>();
Assert.That(trajectories, Is.Not.Null);
Assert.That(combatRenderer, Is.Not.Null);
var shotDeadline = Time.realtimeSinceStartup + 20f;
while (Time.realtimeSinceStartup < shotDeadline &&
@ -823,7 +828,10 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
Convert.ToSingle(fieldViewport.GetType().GetProperty("MaxX")?.GetValue(fieldViewport)),
Convert.ToSingle(fieldViewport.GetType().GetProperty("MaxY")?.GetValue(fieldViewport)),
Convert.ToInt32(fieldSplats.GetType().GetProperty("Count")?.GetValue(fieldSplats)),
playerRendererFacts);
playerRendererFacts,
root.GetComponentsInChildren<EveUnityPlayableWorldEntityMarker>(includeInactive: true)
.Select(marker => PresentedEntityFact.From(camera, marker))
.ToArray());
}
finally
{
@ -893,7 +901,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
float fieldViewportMaxX,
float fieldViewportMaxY,
int fieldSplatCount,
RendererFact[] playerRendererFacts)
RendererFact[] playerRendererFacts,
PresentedEntityFact[] presentedEntityFacts)
{
var path = Environment.GetEnvironmentVariable("EVEUNITY_WITNESS_FACTS_PATH");
if (string.IsNullOrWhiteSpace(path)) return;
@ -961,6 +970,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
fieldViewportMaxY = fieldViewportMaxY,
fieldSplatCount = fieldSplatCount,
playerRenderers = playerRendererFacts,
presentedEntities = presentedEntityFacts,
mapChannelRendererCount = mapChannelRendererCount,
mapChangedPixels = mapChangedPixels,
pilotCameraExcludesMapChannel = pilotCameraExcludesMapChannel,
@ -1034,6 +1044,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
public float fieldViewportMaxY;
public int fieldSplatCount;
public RendererFact[] playerRenderers;
public PresentedEntityFact[] presentedEntities;
public int mapChannelRendererCount;
public int mapChangedPixels;
public bool pilotCameraExcludesMapChannel;
@ -1110,6 +1121,45 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
}
}
[Serializable]
private sealed class PresentedEntityFact
{
public string entityId;
public string entityKind;
public string label;
public string assetRef;
public string worldPosition;
public string worldScale;
public int rendererCount;
public int enabledRendererCount;
public bool intersectsPilotFrustum;
public float viewportWidth;
public float viewportHeight;
public static PresentedEntityFact From(Camera camera, EveUnityPlayableWorldEntityMarker marker)
{
var renderers = marker.GetComponentsInChildren<Renderer>(includeInactive: true);
MeasureViewportCoverage(camera, renderers, out var width, out var height);
var planes = GeometryUtility.CalculateFrustumPlanes(camera);
return new PresentedEntityFact
{
entityId = marker.EntityId,
entityKind = marker.EntityKind,
label = marker.Label,
assetRef = marker.AssetRef,
worldPosition = FormatVector(marker.transform.position),
worldScale = FormatVector(marker.transform.lossyScale),
rendererCount = renderers.Length,
enabledRendererCount = renderers.Count(renderer => renderer.enabled && renderer.gameObject.activeInHierarchy),
intersectsPilotFrustum = renderers.Any(renderer =>
renderer.enabled && renderer.gameObject.activeInHierarchy &&
GeometryUtility.TestPlanesAABB(planes, renderer.bounds)),
viewportWidth = width,
viewportHeight = height
};
}
}
[Serializable]
private sealed class MaterialFact
{

View file

@ -5,8 +5,8 @@
The released-package witness passes in separate cold-lowering and warm-gameplay
profiles with:
- `org.gamecult.eve.unity-scene` `0.3.50`, commit
`7c8442e12264806a53a9e0e08b7b090dcddb8c90`;
- `org.gamecult.eve.unity-scene` `0.3.51`, commit
`21ac39e7bdfca9d81a0b7d89834f7e9da60aaad6`;
- `org.gamecult.eve.plugin-fields` `0.2.3`, commit
`c5a4a75c1b727499b16c2dae1895f29e2a9f72f0`;
- `org.gamecult.eve.surface` `0.2.2`, commit
@ -18,8 +18,9 @@ profiles with:
- the generic `ReleaseConsumerProject` client connected directly to the
Aetheria daemon.
Evidence is in `artifacts/aetheria-daemon-cultlib-1014-cold-final` and
`artifacts/aetheria-daemon-cultlib-1014-warm-final`. The warm PlayMode test
Current celestial-package evidence is in
`artifacts/aetheria-daemon-celestial-cold`; the retained cold and warm witness
documents distinguish transfer from gameplay. The warm PlayMode test
passed and recorded provider-owned reconciled movement, look, targeting,
tractor press, tractor release, contact-gated cargo collection, and action
receipts. The daemon-owned look direction reached the SoA body rotation,
@ -32,7 +33,7 @@ direction, color, and intensity; the generic camera rig lowers that contract to
the only live directional light (`0.75` intensity).
Aetheria also advertises the original undocked `ARPG.unity` Third Person Rig:
entity-forward perspective follow, `30` unit distance, `60` degree vertical
field of view, target screen position `0.64,0.81`, zero position damping, and
field of view, canonical bottom-origin target screen position `0.64,0.19`, zero position damping, and
`1`-`4096` clip planes. Its generic `aim.convergence-point.v1` relation makes
the optical axis reach the daemon-published aim point while preserving that
entity framing. The generic camera rig lowers both constraints without
@ -66,11 +67,11 @@ daemon lock progress `1.0`; Unity does not manufacture or smooth that value.
Camera-channel facts:
- provider-authored player renderers: `13`, including the lowered tractor effect;
- pilot changed pixels: `196,179`;
- pilot average luminance: `0.0993295`;
- pilot bright pixels: `1,348`;
- pilot changed pixels: `225,548`;
- pilot average luminance: `0.119513`;
- pilot bright pixels: `97,617`;
- map-channel renderers: `10`;
- map changed pixels: `4,627`;
- map changed pixels: `4,723`;
- native cockpit progress bars: `7`;
- daemon tractor power at capture: `1.0` after the held input completed its
authored ramp;
@ -86,11 +87,22 @@ Camera-channel facts:
pixels;
- the map camera renders exactly the advertised map layer.
The daemon also publishes the current zone's celestial presentation through the
same generic entity SoA generation as ordinary world entities. The current warm
witness records eleven sun/planet/gas-giant rows and eighteen asteroid rows.
Every row resolved a provider asset with enabled native renderers, and seven
celestial instances intersected the pilot frustum. These identities are
presentation-only and cannot receive gameplay commands. EveUnity contains no
Aetheria or celestial branch; release `0.3.51` fixes the generic prefab wrapper
so semantic instance scale composes with, rather than overwrites, provider-local
scale.
Visual inspection confirms that map glyphs are absent from the pilot frame and
present in the map-only frame. This is transport, authority, field-production,
and lowering proof, not visual parity: the current pilot capture is nearly black
with sparse clipped geometry instead of the fossil's bright blue gravity-shaped
fog sea. Release `0.3.50` includes generic lowering for Eve Fields `0.2.3`'s
and lowering proof, not visual parity: the current pilot capture contains the
blue fog field and provider geometry, but nearby ships remain too dark and the
celestial composition lacks the fossil capture's readable close body. Release
`0.3.51` includes generic lowering for Eve Fields `0.2.3`'s
`AnimatedRadialCosine` source alongside `PowerPulse`, dither-scale,
temporal-history, and finite-look-at semantics. Aetheria publishes the fossil
global animated simplex/cellular/ambient producer stack, body-owned radial wave
@ -146,13 +158,14 @@ Primary artifacts:
## Cold delivery proof
The `cold-start-lowering` profile starts with zero bodies and zero partials. It
receives the `46,412,384` byte Unity bundle through the managed
receives the `55,529,775` byte Unity bundle through the managed
`cultmesh.content.v1` session, verifies SHA-256
`f5960f240ecfd56de417e8e51fde34cfb962fc6fcf0840cc373190e7dbc6048f`,
`5cb34be9b29f533ddfea89a439f43170c3691538b2dba9578d1f96ff91cc0b34`,
atomically promotes one `.body`, and leaves zero partials under the unchanged
300-second deadline. The full witness took `84.991` seconds; the Unity test took
`43.212` seconds. It then lowered provider assets, movement, environment, four
field layers across `127` composites, and both camera channels. The pilot camera
300-second deadline. Including a clean provider-bundle build, the full witness
took `263.477` seconds; the Unity test took `48.083` seconds. It then lowered
provider assets, movement, environment, four field layers across `125`
composites, and both camera channels. The pilot camera
excluded map objects and the map camera included them.
Cold asset acquisition and transient gameplay are deliberately separate proof

View file

@ -13,7 +13,7 @@ param(
)
$ErrorActionPreference = "Stop"
$expectedEveUnityCommit = "7c8442e12264806a53a9e0e08b7b090dcddb8c90"
$expectedEveUnityCommit = "21ac39e7bdfca9d81a0b7d89834f7e9da60aaad6"
$expectedEveFieldsCommit = "c5a4a75c1b727499b16c2dae1895f29e2a9f72f0"
$expectedEveUnityUiToolkitCommit = "4d0cbe0185bdc4fc65eb63503a7c5cb578539669"
$expectedCultLibCommit = "4b7162022a8976f7941b5a7a69acf50f1b6d532b"
@ -246,6 +246,21 @@ try {
[long]$facts.fieldVolumeCompositeCount -le 0) {
throw "Live witness did not prove provider assets, movement, Fields lowering, and camera-channel separation."
}
$presentedCelestials = @($facts.presentedEntities | Where-Object { $_.entityKind -like "celestial.*" })
$presentedBodies = @($presentedCelestials | Where-Object {
$_.entityKind -in @("celestial.sun", "celestial.planet", "celestial.gas-giant")
})
$presentedAsteroids = @($presentedCelestials | Where-Object { $_.entityKind -eq "celestial.asteroid" })
$invalidCelestials = @($presentedCelestials | Where-Object {
[string]::IsNullOrWhiteSpace($_.assetRef) -or
[int]$_.rendererCount -le 0 -or
[int]$_.enabledRendererCount -le 0
})
if ($presentedBodies.Count -le 0 -or $presentedAsteroids.Count -le 0 -or
$invalidCelestials.Count -ne 0 -or
@($presentedCelestials | Where-Object { $_.intersectsPilotFrustum }).Count -le 0) {
throw "Live witness did not prove provider-owned celestial bodies and asteroids reached the generic scene and intersected the pilot frustum. bodies=$($presentedBodies.Count) asteroids=$($presentedAsteroids.Count) invalid=$($invalidCelestials.Count)"
}
if ($witnessProfile -eq "full-session-gameplay" -and
(-not $facts.combatPresentation -or [string]::IsNullOrWhiteSpace($facts.shotId) -or
[double]$facts.lockProgress -le 0.99 -or -not $facts.pickupCollection -or