feat(#184): Slice 3 — Setup-derived mover sphere for the remote de-overlap sweep
The per-tick remote de-overlap sweep used a hardcoded HUMAN collision sphere (0.48 m radius / 1.835 m capsule top) for EVERY creature, so large and small monsters de-overlapped at human spacing (register TS-46). Retail seeds the transition from the object's OWN Setup sphere list scaled by its wire ObjScale (CPhysicsObj::transition 0x00512dc0 -> init_sphere(GetNumSphere, GetSphere, m_scale); ObjScale from set_description 0x00514f40). Slice 3 (one call site, no signature change): before the Path B ResolveWithTransition call, read the creature's Setup-derived dims via the existing GetSetupCylinder helper -- (setup.Radius, setup.Height) x ObjScale, the same source the local player and the moveto/sticky radii already use, consistent with the spawn-time shadow registration's entScale -- and pass them as sphereRadius/sphereHeight. Fall back to the human capsule when GetSetupCylinder returns (0,0) for a shapeless / unresolvable Setup (a zero radius would degenerate the sweep). The player call site is unchanged (the player IS the human Setup). stepUp/stepDown stay 0.4 m (retail derives those from the Setup too -- an adjacent divergence left as-is). Big monsters now spread wider, small ones tighter -- the de-overlap distance tracks each creature's true radius. Test: RemoteDeOverlapMechanismTests.ConvergingLargeCreatures_DeOverlapWiderThanHuman (an R=0.9 pair settles ~1.8 m -- materially wider than the human 0.96 m contact -- proving the sweep de-overlaps at the radius it is given). Register: narrows TS-46 (remotes no longer human-dimmed; residual = the two-scalar reconstruction vs retail's sphere list, plus the 0.4 m step heights). Core 2621 / App 741 green. Research: workflow wf_e8306250-21b (3-agent read-only sweep: acdream data source / retail init_sphere reference / minimal-edit path). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
37a94e1fa4
commit
f51c1dffa5
3 changed files with 72 additions and 12 deletions
|
|
@ -74,9 +74,14 @@ public class RemoteDeOverlapMechanismTests
|
|||
Velocity = Vector3.Zero,
|
||||
};
|
||||
|
||||
/// <summary>One catch-up-step + sweep for one creature; returns the resolved position.</summary>
|
||||
/// <summary>One catch-up-step + sweep for one creature (human dims); returns the resolved position.</summary>
|
||||
private Vector3 StepToward(PhysicsEngine engine, uint id, PhysicsBody body, ref uint cell,
|
||||
Vector3 target)
|
||||
=> StepToward(engine, id, body, ref cell, target, R, H);
|
||||
|
||||
/// <summary>One catch-up-step + sweep with an explicit mover radius/height (Slice 3).</summary>
|
||||
private Vector3 StepToward(PhysicsEngine engine, uint id, PhysicsBody body, ref uint cell,
|
||||
Vector3 target, float radius, float height)
|
||||
{
|
||||
Vector3 pre = body.Position;
|
||||
Vector3 flatTarget = new Vector3(target.X, target.Y, pre.Z);
|
||||
|
|
@ -84,7 +89,7 @@ public class RemoteDeOverlapMechanismTests
|
|||
float dist = delta.Length();
|
||||
Vector3 post = dist <= StepPerTick ? flatTarget : pre + delta / dist * StepPerTick;
|
||||
|
||||
var r = engine.ResolveWithTransition(pre, post, cell, R, H, StepUp, StepDown,
|
||||
var r = engine.ResolveWithTransition(pre, post, cell, radius, height, StepUp, StepDown,
|
||||
isOnGround: true, body: body,
|
||||
moverFlags: ObjectInfoState.EdgeSlide,
|
||||
movingEntityId: id);
|
||||
|
|
@ -256,4 +261,46 @@ public class RemoteDeOverlapMechanismTests
|
|||
$"a stall-blip escaped the sweep (monster popped into its neighbour): " +
|
||||
$"maxSpike A={maxSpikeA:F3} B={maxSpikeB:F3} m (limit 0.30)");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Slice 3 (#184): the de-overlap distance must SCALE with the mover's radius —
|
||||
/// a LARGE creature (bigger Setup sphere) spreads WIDER than a human, a small one
|
||||
/// tighter. Production now passes each creature's Setup-derived radius/height
|
||||
/// (GameWindow.GetSetupCylinder × ObjScale) into this exact sweep instead of the
|
||||
/// hardcoded human 0.48/1.835. Register + sweep two LARGE creatures (R=0.9) and
|
||||
/// assert they settle near 2×0.9 = 1.8 m — materially wider than the human 0.96 m
|
||||
/// contact — proving the sweep de-overlaps at the radius it is given (the property
|
||||
/// Slice 3 relies on).
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ConvergingLargeCreatures_DeOverlapWiderThanHuman()
|
||||
{
|
||||
const float bigR = 0.9f, bigH = 3.2f;
|
||||
const float bigContact = 2f * bigR; // 1.80 m centre-to-centre when touching
|
||||
var engine = BuildEngine();
|
||||
uint idA = 0xA1u, idB = 0xB2u;
|
||||
var target = new Vector3(10f, 10f, bigR); // shared centre → coincide if reached
|
||||
var a = GroundedBody(new Vector3(7.5f, 10f, bigR)); // start well clear (2.5 m each side)
|
||||
var b = GroundedBody(new Vector3(12.5f, 10f, bigR));
|
||||
engine.ShadowObjects.Register(idA, 0u, a.Position, Quaternion.Identity, bigR,
|
||||
0f, 0f, Lb, ShadowCollisionType.Sphere, 0f, 1f, 0u, EntityCollisionFlags.IsCreature, isStatic: false);
|
||||
engine.ShadowObjects.Register(idB, 0u, b.Position, Quaternion.Identity, bigR,
|
||||
0f, 0f, Lb, ShadowCollisionType.Sphere, 0f, 1f, 0u, EntityCollisionFlags.IsCreature, isStatic: false);
|
||||
uint cellA = Cell, cellB = Cell;
|
||||
|
||||
for (int tick = 0; tick < 300; tick++)
|
||||
{
|
||||
var pa = StepToward(engine, idA, a, ref cellA, target, bigR, bigH);
|
||||
engine.ShadowObjects.UpdatePosition(idA, pa, Quaternion.Identity, 0f, 0f, Lb, seedCellId: cellA);
|
||||
var pb = StepToward(engine, idB, b, ref cellB, target, bigR, bigH);
|
||||
engine.ShadowObjects.UpdatePosition(idB, pb, Quaternion.Identity, 0f, 0f, Lb, seedCellId: cellB);
|
||||
}
|
||||
|
||||
float sep = Vector2.Distance(new(a.Position.X, a.Position.Y), new(b.Position.X, b.Position.Y));
|
||||
_out.WriteLine($"large-creature sep={sep:F3} m (big contact {bigContact:F2}, human contact {ContactDist:F2})");
|
||||
Assert.True(sep >= bigContact - 0.20f,
|
||||
$"large creatures must de-overlap near their 2R contact ({bigContact:F2} m); got {sep:F3} m");
|
||||
Assert.True(sep > ContactDist + 0.4f,
|
||||
$"large creatures must spread materially WIDER than the human contact ({ContactDist:F2} m); got {sep:F3} m");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue