Floater fixtures: the grab-point test and the wiring verify run over a moving well

PickupTests builds the zone over a sun and a planet on a rail, asserts the field differs between the ship's point and the item's and between start and end of the run, and checks each grab event at the zone time it was published. DrawnPoseWiringVerify gets a sun and a planet near the pickup and mine, requires the field under each to move with the drawn time, and checks the pickup's y as well as the mine's. Not compiled or run yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-17 13:47:52 +02:00
commit c631e09fe8
2 changed files with 65 additions and 7 deletions

View file

@ -116,7 +116,23 @@ namespace Aetheria.EditorTools
cache.FlushAsync().Wait();
var ledger = new ProvenanceLedger();
var items = new ItemManager(cache, ledger, settings, _ => { });
var zone = new Zone(items, new PlanetSettings(), new ZonePack(), null, null);
// A sun and a planet on a moving rail round it, both near the bodies below: the field under a floater changes with the
// drawn time, so a presenter that samples it at the step's time, drops it, or reads lead 0 for the height draws a different y.
var sunOrbit = cache.Upsert(new OrbitData { FixedPosition = new float2(-60, -40) }).Key;
var planetOrbit = cache.Upsert(new OrbitData { Parent = new CultRecordRef<OrbitData>(sunOrbit), Distance = 40f, Phase = .3f }).Key;
var pack = new ZonePack { Radius = 5000f, Mass = 10000f };
pack.Orbits.Add(new CultRecordRef<OrbitData>(sunOrbit));
pack.Orbits.Add(new CultRecordRef<OrbitData>(planetOrbit));
pack.Planets.Add(new CultRecordRef<BodyData>(cache.Upsert(new PlanetData { Name = "Wiring Sun", Orbit = new CultRecordRef<OrbitData>(sunOrbit), Mass = 400f }).Key));
pack.Planets.Add(new CultRecordRef<BodyData>(cache.Upsert(new PlanetData { Name = "Wiring Planet", Orbit = new CultRecordRef<OrbitData>(planetOrbit), Mass = 100f }).Key));
var curves = new PlanetSettings
{
BodyRadius = new ExponentialCurve(),
WellStrength = new ExponentialCurve { Multiplier = 1f, Exponent = 1f },
RocheLimit = new ExponentialCurve { Constant = 2f }
};
var zone = new Zone(items, curves, pack, null, null);
var rootObject = new GameObject("Wiring Zone Root");
var rendererObject = new GameObject("Wiring Zone Renderer");
@ -162,6 +178,12 @@ namespace Aetheria.EditorTools
var mineVelocity = mine.Body.TotalVelocity;
Require(Mathf.Abs(pickupVelocity.x) > 1f && Mathf.Abs(mineVelocity.y) > 1f, "The fixture's bodies stopped: a lead would not move them.");
// The field under each floater really is a function of the drawn time here, by more than the tolerance at the largest lead.
const float LargestLead = .015f;
foreach (var at in new[] { floating.Body.Position + pickupVelocity * LargestLead, mine.Body.Position + mineVelocity * LargestLead })
Require(Mathf.Abs(DrawAhead.Height(zone, at, LargestLead) - zone.GetHeight(at, zone.ExactTime)) > 5 * Tolerance,
"The fixture's field is flat under a floater: a drawn time would not move its height.");
Vector2 baseline = default;
foreach (var leadSeconds in new[] { 0f, .008f, .015f })
{
@ -176,6 +198,9 @@ namespace Aetheria.EditorTools
Require(Mathf.Abs(seen.x - want.x) < Tolerance && Mathf.Abs(seen.z - want.y) < Tolerance,
$"ItemPickup at lead {lead}: drawn x/z {seen.x},{seen.z}, the step plus velocity times lead {want.x},{want.y}.");
Require(Mathf.Abs(seen.y - DrawAhead.FloaterHeight(zone, settings, new float2(want.x, want.y), lead)) < Tolerance,
$"ItemPickup y {seen.y} is not on the floater layer.");
seen = mineInstance.transform.position;
want = mine.Body.Position + mineVelocity * lead;
Require(Mathf.Abs(seen.x - want.x) < Tolerance && Mathf.Abs(seen.z - want.y) < Tolerance,