fix(items): use retail cylinder range for loot windows
Keep external-container visibility tied to the signed surface gap between the player and container physics cylinders, matching gmExternalContainerUI's authored UseRadius range watcher. This prevents a valid ViewContents response from being closed at ACE's natural approach endpoint. Port Position::cylinder_distance and ACCWeenieObject::ObjectsInRange into Core with conformance coverage for 3-D separation, overlap, mode precedence, and inclusive boundaries. Release build succeeds and all 5,895 tests pass with five intentional skips. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
e6dd8bf6fa
commit
0f82a08f0a
6 changed files with 199 additions and 50 deletions
|
|
@ -17,15 +17,10 @@ namespace AcDream.Core.Tests.Physics.Motion;
|
|||
/// available, not re-ported here).
|
||||
///
|
||||
/// <para>
|
||||
/// The retail signature's exact combination math for radius/height beyond
|
||||
/// "edge-to-edge, own+target cylinders" is not spelled out in the raw (BN
|
||||
/// garbles the x87 plumbing) — ported per the PDB argument ORDER
|
||||
/// (own radius/height, own position, target radius/height, target
|
||||
/// position) with the standard cylinder-distance shape: horizontal
|
||||
/// (planar) distance minus the sum of the two radii (clamped at 0), since
|
||||
/// that is the only shape consistent with "edge-to-edge" and with
|
||||
/// <c>distance_to_object</c>'s ctor default of 0.6 (melee range from
|
||||
/// surface to surface, not center to center).
|
||||
/// The exact branch structure is visible at named-retail
|
||||
/// <c>Position::cylinder_distance @ 0x005A97F0</c> and independently matches
|
||||
/// ACE <c>Physics.Common.Position.CylinderDistance</c>. It uses full 3D center
|
||||
/// distance, both radii, both heights, and returns signed overlap.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class MoveToMathCylinderDistanceTests
|
||||
|
|
@ -42,14 +37,14 @@ public sealed class MoveToMathCylinderDistanceTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void TwoCylinders_Overlapping_ClampsAtZero_NoNegativeDistance()
|
||||
public void TwoCylinders_Overlapping_ReturnsSignedThreeDimensionalOverlap()
|
||||
{
|
||||
// centers 1 unit apart, radii 5 and 5 → would be -9, clamps to 0
|
||||
// radial gap = 1 - 10 = -9; vertical gap = 0 - 2 = -2.
|
||||
float d = MoveToMath.CylinderDistance(
|
||||
ownRadius: 5f, ownHeight: 2f, ownPos: Vector3.Zero,
|
||||
targetRadius: 5f, targetHeight: 2f, targetPos: new Vector3(1f, 0f, 0f));
|
||||
|
||||
Assert.Equal(0f, d, 3);
|
||||
Assert.Equal(-MathF.Sqrt(85f), d, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -63,29 +58,33 @@ public sealed class MoveToMathCylinderDistanceTests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void TwoCylinders_IgnoresVerticalSeparation_PlanarOnly()
|
||||
public void TwoCylinders_VerticallyAndRadiallySeparated_CombinesBothGaps()
|
||||
{
|
||||
// Same X/Y, large Z separation — cylinder_distance in retail's own
|
||||
// callers (GetCurrentDistance) is used for horizontal arrival gates;
|
||||
// the Z axis is height, not part of the radial edge-to-edge gap.
|
||||
float d1 = MoveToMath.CylinderDistance(
|
||||
ownRadius: 1f, ownHeight: 2f, ownPos: new Vector3(0, 0, 0),
|
||||
targetRadius: 1f, targetHeight: 2f, targetPos: new Vector3(5f, 0f, 0f));
|
||||
float d2 = MoveToMath.CylinderDistance(
|
||||
ownRadius: 1f, ownHeight: 2f, ownPos: new Vector3(0, 0, 50f),
|
||||
targetRadius: 1f, targetHeight: 2f, targetPos: new Vector3(5f, 0f, -50f));
|
||||
// full center gap = 5, radial gap = 3; vertical gap = 4 - 2 = 2.
|
||||
float d = MoveToMath.CylinderDistance(
|
||||
ownRadius: 1f, ownHeight: 2f, ownPos: Vector3.Zero,
|
||||
targetRadius: 1f, targetHeight: 2f, targetPos: new Vector3(3f, 0f, 4f));
|
||||
|
||||
Assert.Equal(d1, d2, 3);
|
||||
Assert.Equal(3f, d1, 3); // 5 - 1 - 1
|
||||
Assert.Equal(MathF.Sqrt(13f), d, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SamePosition_ZeroDistance_ClampsNotNegative()
|
||||
public void SamePosition_ReturnsSignedOverlap()
|
||||
{
|
||||
float d = MoveToMath.CylinderDistance(
|
||||
ownRadius: 0.5f, ownHeight: 2f, ownPos: Vector3.Zero,
|
||||
targetRadius: 0.5f, targetHeight: 2f, targetPos: Vector3.Zero);
|
||||
|
||||
Assert.Equal(0f, d, 3);
|
||||
Assert.Equal(-MathF.Sqrt(5f), d, 3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OppositeGapSigns_ReturnsRadialGapVerbatim()
|
||||
{
|
||||
float d = MoveToMath.CylinderDistance(
|
||||
ownRadius: 5f, ownHeight: 1f, ownPos: Vector3.Zero,
|
||||
targetRadius: 5f, targetHeight: 1f, targetPos: new Vector3(0f, 0f, 3f));
|
||||
|
||||
Assert.Equal(-7f, d, 3);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue