fix #182: port CSphere collision family — retail-faithful crowd wiggle (retires TS-45)
Humanoid creatures/players collide as body Spheres (ShadowShapeBuilder emits Sphere-type shadows for a Setup with Spheres + no CylSpheres), so player-vs-monster crowd contact ran through Transition.SphereCollision — a hand-rolled 3-D wall-slide (register TS-45), NOT a port of retail CSphere::intersects_sphere. It shaved no eps, force-pushed each contact RADIALLY to a fixed combinedR+1cm shell, ignored the head sphere, and always returned Slid. In a crowd the opposing radial de-penetration pushes from neighbours fight each other -> the player wedges and can't wiggle free (the user's live report). Port the full CSphere family verbatim — dispatcher 0x00537A80 + step_sphere_up / slide_sphere / land_on_sphere / collide_with_point / step_sphere_down — the direct analog of the 2026-07-05 CCylSphere port (#172). The grounded slide now routes through the shared crease SlideSphere (0x00537440, #116-Ghidra-confirmed) -> tangential shuffle along the contact toward gaps, retail-faithful. isCreature (target creature/missile) gates OFF the stand-on/land-on branches (2 & 5). ACE Sphere.cs = readable oracle; pseudocode doc 2026-07-07-csphere-collision-family. Retail-faithfulness verified: CTransition::validate_transition (0x0050aa70:272593) reverts curr_pos on any non-clean-OK step, so a deep-mutual-overlap start wedges in retail too — the realistic crowd-edge graze slides free (SphereCollisionFamilyTests slide-around trajectory: player grazes a creature's SW, curves around its west side, continues N). TS-45 retired, AP-84 added (PerfectClip TOI dead in M1.5). Core 2603/0, App 741/0. Pending user visual gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0cbe1102d9
commit
96ae274081
6 changed files with 908 additions and 85 deletions
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using AcDream.Core.Physics;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using DatReaderWriter.Enums;
|
||||
|
|
@ -90,4 +91,32 @@ public class ShadowShapeBuilderShapeSourceTests
|
|||
|
||||
Assert.Empty(shapes);
|
||||
}
|
||||
|
||||
// 2026-07-07 — the PREMISE of the player-vs-monster crowd-collision fix (the
|
||||
// CSphere family port): a humanoid Setup carries body Spheres and NO
|
||||
// CylSpheres, so FromSetup emits Sphere-type shadows → collision runs through
|
||||
// Transition.SphereCollision (the retail CSphere::intersects_sphere family),
|
||||
// NOT the cylinder path. Mirrors the human Setup 0x02000001 (two body spheres
|
||||
// at 0.475 / 1.350, r=0.48 — TS-46 / the physics digest). If this ever flips
|
||||
// to CylSphere-first, the crowd fix would be aimed at the wrong dispatcher.
|
||||
[Fact]
|
||||
public void Setup_WithBodySpheres_NoCylSpheres_EmitsSphereShapes()
|
||||
{
|
||||
var setup = new Setup
|
||||
{
|
||||
CylSpheres = new List<CylSphere>(),
|
||||
Spheres = new List<Sphere>
|
||||
{
|
||||
new Sphere { Origin = new Vector3(0f, 0f, 0.475f), Radius = 0.48f },
|
||||
new Sphere { Origin = new Vector3(0f, 0f, 1.350f), Radius = 0.48f },
|
||||
},
|
||||
Parts = new List<QualifiedDataId<GfxObj>>(),
|
||||
PlacementFrames = new Dictionary<Placement, AnimationFrame>(),
|
||||
};
|
||||
|
||||
var shapes = ShadowShapeBuilder.FromSetup(setup, entScale: 1f, hasPhysicsBsp: _ => false);
|
||||
|
||||
Assert.Equal(2, shapes.Count);
|
||||
Assert.All(shapes, s => Assert.Equal(ShadowCollisionType.Sphere, s.CollisionType));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue