The player stands on, bumps into and pushes bodies, and is shoved by them #20

Merged
agra merged 6 commits from task/3902-the-player-stands-on-bumps-into-and-push into master 2026-10-30 09:44:05 +02:00
Owner

Tracker: #3902

Step 3 of plan #3865 (Physics): the player meets the rigid bodies.

  • Solids (src/physics/solids.sx) is a view of the map's collision world and the bodies at their poses, answering the ray, the capsule sweep and the capsule overlap the movement code asks. A hit names a map triangle or a body, a tie going to the triangle and then to the lower index. A box's or hull's faces enter as posed triangles with each face's diagonals inner, swept and overlapped by the collision world's own sweepTriangle and overlapTriangle, so a resting crate meets the player as a static block of its shape does. A sphere or capsule meets it by the closest points of their cores, its normal along the gap. An overlap carries the face normal the edge and step rules read. With no bodies every answer is the collision world's.
  • Escapes. A capsule a body has moved into leaves it by Solids.escape: of the moves out of each body it overlaps along that body's ways out (its deepest overlap's normal, its own three axes both ways, and the level part of each), the least that the map and the other bodies let it make whole. Each move's length comes from the closest points of the capsule's core and the body's surface, advanced along the way out to where the capsule comes within TOUCH of the body, from either side. So a body that comes down onto a player standing on the map moves it aside along the map, never into it.
  • Movement (src/sim/player.sx) queries Solids, which the server builds each tick from the bodies' poses at the tick's start. Its push-out takes the map's overlaps first, the deepest first, exactly as before, and then each body's escape. The player stands on and climbs bodies as on blocks, and does not ride them. Movement tests with no bodies step through tests/support/alone.sx.
  • Pushing. After the players move, the server hands the physics world each living player's capsule at its new feet, moving at the velocity its command asks for (walk, sprint, crouch or swim). In the solver each is a body of infinite mass whose contacts come after the contacts between bodies and before the map's, and it pushes each body it touches with at most 500 N in all, shared among their contact points, without friction or bounce. It wakes a sleeping body only while it moves into it, and joins no island. A body moving into a player overlaps its capsule, and the player's push-out moves it aside at its next tick.
  • The README's Playing section says the player stands on bodies and pushes them, and that a body coming down onto it moves it aside along the ground.

Checks

  • tests/solids.sx: a crate's sweeps and overlaps (2000 of each) equal those of the same box built as static triangles; ties go to the triangle, then the lower body; overlaps carry their face's normal; a sphere's and a capsule's contacts and rays sit at their surfaces along the gap; a capsule resting on a capsule body moves along it and away freely and meets it at once moving into it. Escapes from bodies come down onto a capsule standing on a floor: a crate's least way out the floor lets through (0.55 m along -X where 0.5 m down is shorter); another way when a second crate lies against that one; a level way out of a crate leaning on every axis; the gap's direction, by its depth, out of a crate's upright edge; a level way along a ball's axis; and just outside a turned crate whose far closest points tie within rounding.
  • tests/sim_push.sx, through the server on flat ground: a 20 kg crate is pushed at 4.0 m/s 1 s on, the player behind it; a crouching player and a swimmer on the bed of a 1.5 m pool push it at 2.0 and 2.5 m/s, each within 10% at every tick from 0.5 s to 1 s on; a 90 kg crate slides, a 110 kg one does not move and stops the player; a player jumps onto a crate and stands on it, and walks across and off it, the crate asleep throughout; a crate a player stands still against stays asleep; a 100 kg box sliding into a standing player shoves it aside within 10 ticks, its capsule never inside the box after push-out; a 0.8 m crate of 20 kg dropped 2 m and a 1.2 m one of 60 kg dropped 0.3 m onto a standing player leave its feet on the floor and its capsule outside the crate after every tick; a turned crate sunk into a player's head is left along the floor; a box slides through a dead player; a tower topples; two servers send byte-identical snapshots for 600 ticks.
  • Before the escapes, at 2a2d049, the two drop cases sank the feet 0.6 m under the floor and left the capsule 0.3 m inside the crate. A scratch probe of 216 drops (10, 60 and 150 kg; 0.6, 0.8 and 1.2 m crates; drops of 0.3 to 2.5 m; standing and crouched; 0 to 0.3 m off centre) sank the feet in 85 and left them under the floor in 32 at 2a2d049, and at the head none, with the capsule outside the crate after every tick. 27,124 random overlaps of turned boxes, balls and capsule bodies with a capsule standing on a floor beside a wall each escape to a capsule clear of everything.
  • On the first map, 160 walks and sprints into the 20 settled props put the feet at most 1.8 mm under the terrain (0.58 m at 2a2d049), and a player started inside barrel 12 never goes under it. In 25 of those walks the move that follows the push-out still ends a tick up to 3.1 cm inside a crate. That comes from sweepTriangle in src/physics/collision.sx, which this step leaves as it is: while a triangle's closest point lies on an inner diagonal it steps by the face normal, which can overshoot the face's first touch. With every inner bit cleared, the same walks end at most 53 µm inside a crate and never under the terrain. The same overshoot lets sweeps through a plain map quad: 4,973 of 128,822 long sweeps that touch one miss it, and 8 of 11,485 moves of 0.12 m. Fixing it changes movement without bodies, so it is left for a task of its own.
  • Movement without bodies is bit-identical to master: in git archive arms of master and the head, every step of tests/sim_move.sx (13,682) and tests/sim_swim.sx (2,354) and of 64 three-second sprints from the first map's spawn markers (11,520) printed feet, velocity, flags, eye, lift and climb as raw bits, with no difference.
  • Mutants, one at a time in a git archive arm of the head, against tests/solids.sx, tests/sim_push.sx, tests/sim_bodies.sx and tests/first_map_bodies.sx: all 22 fail a test. They are the escape with no free check, with a free check against the map alone, taking the first free way rather than the least, with no level parts, no own axes or no deepest normal, with a one-sided advance or with the reverse sweep's advance; the push-out with no escapes, and with one deepest-first loop over every overlap; the asked velocity walking whatever the mode, with no swim branch, with no crouch branch, and the allowed velocity; sweepRound with no leave rule; the push cap removed, and a cap per contact point; waking on any touch, and never; the sweep's tie going to the body; no inner diagonals; and the overlap normal in place of the face normal. An earlier run found two survivors: dropping the per-body bounds check in Solids.sweep, equivalent by construction; and solving the players' contacts after the map's, which changes no test (in a probe a 5 kg crate squeezed against a wall went 12.3 mm in on one tick with the plan's order and 2.8 mm with players last).
  • sak-gate full passed at 2a2d049 (gate run 906), and at 0f49b1f (gate run 914), every one of its 36 checks.
Tracker: [#3902](https://sak.swipelab.com/tasks/3902) Step 3 of plan #3865 (Physics): the player meets the rigid bodies. - **`Solids`** (`src/physics/solids.sx`) is a view of the map's collision world and the bodies at their poses, answering the ray, the capsule sweep and the capsule overlap the movement code asks. A hit names a map triangle or a body, a tie going to the triangle and then to the lower index. A box's or hull's faces enter as posed triangles with each face's diagonals inner, swept and overlapped by the collision world's own `sweepTriangle` and `overlapTriangle`, so a resting crate meets the player as a static block of its shape does. A sphere or capsule meets it by the closest points of their cores, its normal along the gap. An overlap carries the face normal the edge and step rules read. With no bodies every answer is the collision world's. - **Escapes.** A capsule a body has moved into leaves it by `Solids.escape`: of the moves out of each body it overlaps along that body's ways out (its deepest overlap's normal, its own three axes both ways, and the level part of each), the least that the map and the other bodies let it make whole. Each move's length comes from the closest points of the capsule's core and the body's surface, advanced along the way out to where the capsule comes within `TOUCH` of the body, from either side. So a body that comes down onto a player standing on the map moves it aside along the map, never into it. - **Movement** (`src/sim/player.sx`) queries `Solids`, which the server builds each tick from the bodies' poses at the tick's start. Its push-out takes the map's overlaps first, the deepest first, exactly as before, and then each body's escape. The player stands on and climbs bodies as on blocks, and does not ride them. Movement tests with no bodies step through `tests/support/alone.sx`. - **Pushing.** After the players move, the server hands the physics world each living player's capsule at its new feet, moving at the velocity its command asks for (walk, sprint, crouch or swim). In the solver each is a body of infinite mass whose contacts come after the contacts between bodies and before the map's, and it pushes each body it touches with at most 500 N in all, shared among their contact points, without friction or bounce. It wakes a sleeping body only while it moves into it, and joins no island. A body moving into a player overlaps its capsule, and the player's push-out moves it aside at its next tick. - The README's Playing section says the player stands on bodies and pushes them, and that a body coming down onto it moves it aside along the ground. ## Checks - `tests/solids.sx`: a crate's sweeps and overlaps (2000 of each) equal those of the same box built as static triangles; ties go to the triangle, then the lower body; overlaps carry their face's normal; a sphere's and a capsule's contacts and rays sit at their surfaces along the gap; a capsule resting on a capsule body moves along it and away freely and meets it at once moving into it. Escapes from bodies come down onto a capsule standing on a floor: a crate's least way out the floor lets through (0.55 m along -X where 0.5 m down is shorter); another way when a second crate lies against that one; a level way out of a crate leaning on every axis; the gap's direction, by its depth, out of a crate's upright edge; a level way along a ball's axis; and just outside a turned crate whose far closest points tie within rounding. - `tests/sim_push.sx`, through the server on flat ground: a 20 kg crate is pushed at 4.0 m/s 1 s on, the player behind it; a crouching player and a swimmer on the bed of a 1.5 m pool push it at 2.0 and 2.5 m/s, each within 10% at every tick from 0.5 s to 1 s on; a 90 kg crate slides, a 110 kg one does not move and stops the player; a player jumps onto a crate and stands on it, and walks across and off it, the crate asleep throughout; a crate a player stands still against stays asleep; a 100 kg box sliding into a standing player shoves it aside within 10 ticks, its capsule never inside the box after push-out; a 0.8 m crate of 20 kg dropped 2 m and a 1.2 m one of 60 kg dropped 0.3 m onto a standing player leave its feet on the floor and its capsule outside the crate after every tick; a turned crate sunk into a player's head is left along the floor; a box slides through a dead player; a tower topples; two servers send byte-identical snapshots for 600 ticks. - Before the escapes, at 2a2d049, the two drop cases sank the feet 0.6 m under the floor and left the capsule 0.3 m inside the crate. A scratch probe of 216 drops (10, 60 and 150 kg; 0.6, 0.8 and 1.2 m crates; drops of 0.3 to 2.5 m; standing and crouched; 0 to 0.3 m off centre) sank the feet in 85 and left them under the floor in 32 at 2a2d049, and at the head none, with the capsule outside the crate after every tick. 27,124 random overlaps of turned boxes, balls and capsule bodies with a capsule standing on a floor beside a wall each escape to a capsule clear of everything. - On the first map, 160 walks and sprints into the 20 settled props put the feet at most 1.8 mm under the terrain (0.58 m at 2a2d049), and a player started inside barrel 12 never goes under it. In 25 of those walks the move that follows the push-out still ends a tick up to 3.1 cm inside a crate. That comes from `sweepTriangle` in `src/physics/collision.sx`, which this step leaves as it is: while a triangle's closest point lies on an inner diagonal it steps by the face normal, which can overshoot the face's first touch. With every inner bit cleared, the same walks end at most 53 µm inside a crate and never under the terrain. The same overshoot lets sweeps through a plain map quad: 4,973 of 128,822 long sweeps that touch one miss it, and 8 of 11,485 moves of 0.12 m. Fixing it changes movement without bodies, so it is left for a task of its own. - Movement without bodies is bit-identical to master: in `git archive` arms of master and the head, every step of `tests/sim_move.sx` (13,682) and `tests/sim_swim.sx` (2,354) and of 64 three-second sprints from the first map's spawn markers (11,520) printed feet, velocity, flags, eye, lift and climb as raw bits, with no difference. - Mutants, one at a time in a `git archive` arm of the head, against `tests/solids.sx`, `tests/sim_push.sx`, `tests/sim_bodies.sx` and `tests/first_map_bodies.sx`: all 22 fail a test. They are the escape with no free check, with a free check against the map alone, taking the first free way rather than the least, with no level parts, no own axes or no deepest normal, with a one-sided advance or with the reverse sweep's advance; the push-out with no escapes, and with one deepest-first loop over every overlap; the asked velocity walking whatever the mode, with no swim branch, with no crouch branch, and the allowed velocity; `sweepRound` with no leave rule; the push cap removed, and a cap per contact point; waking on any touch, and never; the sweep's tie going to the body; no inner diagonals; and the overlap normal in place of the face normal. An earlier run found two survivors: dropping the per-body bounds check in `Solids.sweep`, equivalent by construction; and solving the players' contacts after the map's, which changes no test (in a probe a 5 kg crate squeezed against a wall went 12.3 mm in on one tick with the plan's order and 2.8 mm with players last). - `sak-gate full` passed at 2a2d049 (gate run 906), and at 0f49b1f (gate run 914), every one of its 36 checks.
agra merged commit 018b8ff635 into master 2026-10-30 09:44:05 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sx/hulken!20
No description provided.