fix(B.4b): WorldPicker.Pick — handle inside-sphere origin + document normalize contract

Code review flagged two latent correctness bugs in Pick:

1. The single t = -b - sqrt(d) intersection skipped entities whose
   5m bounding sphere contained the ray origin. Realistic at
   point-blank range — if the player stands within ~5m of a door,
   the near-plane sits inside the door's bounding sphere and the
   door becomes unpickable. Standard fix: when t_near < 0 fall
   through to t_far = -b + sqrt(d) (the sphere exit point).

2. The discriminant formula assumes |direction| = 1. BuildRay
   currently normalizes so the assumption holds at the wire, but
   the contract wasn't documented. Added an explicit
   <param name="direction"> note.

New test Pick_RayOriginInsideEntitySphere_StillReturnsServerGuid
covers the inside-sphere case. Suite: 9/9 WorldPicker tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-13 17:52:45 +02:00
parent 221b64186d
commit 5821bdc9ea
2 changed files with 31 additions and 2 deletions

View file

@ -149,4 +149,21 @@ public class WorldPickerTests
Assert.Null(result);
}
[Fact]
public void Pick_RayOriginInsideEntitySphere_StillReturnsServerGuid()
{
// Player ~3m from a door -> camera near-plane sits INSIDE the door's
// 5m bounding sphere. Naive t_near < 0 guard would skip; correct
// behavior is to fall through to t_far (the sphere exit point).
var entity = MakeEntity(0xABCDu, new Vector3(0, 0, -3));
var result = WorldPicker.Pick(
origin: Vector3.Zero,
direction: -Vector3.UnitZ,
candidates: new[] { entity },
skipServerGuid: 0u);
Assert.Equal(0xABCDu, result);
}
}