fix(physics): water depth submersion + sphere-safety-push steep-slope correction
Two coupled physics fixes that together resolve "+Acdream walks on top of water instead of submerged" and "brief Falling animation when running up steep hills". ## 1. Water depth = physics adjustment, not rendering Retail has NO separate water surface mesh. Characters visually submerge in water because ValidateWalkable adds `waterDepth` to its signed-distance check (ACE ObjectInfo.cs:124), letting the character's feet sit below the terrain plane by that amount before the push-up fires. Rendered character below rendered terrain = looks submerged. Our ValidateWalkable didn't carry a waterDepth, so feet were always snapped exactly to the plane. Water cells looked like walking on water. Added: - TerrainSurface now carries per-vertex water flags (bits 2-6 of TerrainInfo → SurfChar lookup) and per-cell classification. - TerrainSurface.SampleWaterDepth(localX, localY) returns 0.0 (dry), 0.45 (partial-water near water corner), 0.9 (entirely water). Deviates from retail's 0.1 fallback for "dry corner of partial-water cell" — that 0.1 destabilizes the "feet exactly on plane" contact-touch check in ValidateWalkable (dist > EPSILON, SetContactPlane skipped, ValidateTransition clears OnWalkable, gravity applies, character micro-falls each frame). - PhysicsEngine.SampleWaterDepth is the world-space wrapper. - FindEnvCollisions samples the per-point depth and forwards it. - ValidateWalkable adds +waterDepth to the signed-distance check (this is the ACE-line-124 port). GameWindow.ApplyLoadedTerrain extracts the low byte of each TerrainInfo ushort and passes it to the TerrainSurface ctor so classification works. ## 2. AdjustOffset safety-push threshold on sloped planes The LocalSphere is positioned at `(0, 0, radius)` — center along world +Z from the character root. On a tilted plane the sphere center's perpendicular distance to that plane is `radius * Normal.Z`, NOT `radius`. The original threshold `dist < radius - EPS` therefore fires spuriously on every slope and the follow-up push-up lifts feet by `radius * (sec θ - 1)` — 7 cm at 30°, 20 cm at 45°, 48 cm at 60°. The steep-slope lift is large enough to break ValidateWalkable's contact-touch check, ValidateTransition then clears OnWalkable, calc_acceleration applies gravity, and the character flickers into the Falling animation for ~0.3s while running uphill. User-observed on steep hills after today's water-depth work made the artifact visible (before that, general hover masked it). Fix: the threshold is `radius * Normal.Z` (the natural resting distance of a Z-axis sphere on the plane). The push fires only when feet are actually penetrating below natural resting, not on any sloped plane. ACE's Transition.cs AdjustOffset has the original threshold but the bug is invisible server-side. All 717 tests green. Water submersion + steep-slope running both user-visually verified. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
40f120617d
commit
f562215e6c
4 changed files with 179 additions and 13 deletions
|
|
@ -110,6 +110,29 @@ public sealed class PhysicsEngine
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sample the per-point water depth at the given world-space XY
|
||||
/// (meters by which the character is allowed to sink below the
|
||||
/// contact plane — 0.9 on fully-flooded water cells, 0.45 on
|
||||
/// partial-water near a water corner, 0.1 on non-water corners of
|
||||
/// partial-water cells, 0 on dry cells). Matches ACE
|
||||
/// <c>ObjCell.get_water_depth</c>. Used by
|
||||
/// <see cref="Transition"/> to visually submerge characters in water
|
||||
/// without needing a separate water surface mesh.
|
||||
/// </summary>
|
||||
public float SampleWaterDepth(float worldX, float worldY)
|
||||
{
|
||||
foreach (var kvp in _landblocks)
|
||||
{
|
||||
var lb = kvp.Value;
|
||||
float localX = worldX - lb.WorldOffsetX;
|
||||
float localY = worldY - lb.WorldOffsetY;
|
||||
if (localX >= 0f && localX < 192f && localY >= 0f && localY < 192f)
|
||||
return lb.Terrain.SampleWaterDepth(localX, localY);
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sample the outdoor terrain plane (Z + sloped normal) at the given
|
||||
/// world-space XY position. The returned <see cref="System.Numerics.Plane"/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue