docs: #338 answered — retail DOES read the authored step height, so this is real
The gating question is closed against the decomp rather than reasoned from our source. CTransition::step_up @0x0050b610 defaults step_up_height to 0.0399999991f and substitutes object_info.step_up_height when (state & 2); step_down has the same shape at 0x0050b852 and reads the authored value unconditionally at 0x0050c232. Two things fall out. Retail's fallback is 0.04, not 0.4 — our value matches neither the fallback nor the authored 0.600/1.500. And state bit 0x2 is OnWalkable, so retail applies the authored height only while standing on walkable ground. We already port that gate faithfully in Transition.DoStepUp, including the stepDownHeight = oi.StepUpHeight assignment that reads oddly but is exactly what retail passes. The gate is not the defect; only the value fed into it is. The local player is the only affected population: its controller fields initialise to 0.4f, while remotes and live entities get Setup-derived values. The property's doc comment names PlayerModeController. ApplyStepHeights as the authoritative writer — that method does not exist anywhere in the tree; the identifier appears once, in the comment. Deliberately NOT fixed. A real writer does exist further out, and RuntimeSetPositionMoverPreparation does compute the Setup-derived value, so the plumbing is there. Whether it runs for the local player or runs and is overwritten is unproven — the probe reading 0.400 says the controller held its default, not why. Setting the field without knowing which path won would be a coin flip. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
677f9a1628
commit
801ff5fd44
1 changed files with 59 additions and 9 deletions
|
|
@ -42,18 +42,68 @@ The human Setup `0x02000001` authors `StepUpHeight = 0.600` and
|
|||
`StepDownHeight = 1.500`. The live `[support]` probe lines show the player
|
||||
resolving with `stepUp=0.400 stepDown=0.400`.
|
||||
|
||||
### What is NOT yet established
|
||||
### ANSWERED 2026-08-06 — retail DOES read the authored field, so this is real
|
||||
|
||||
The gating question is closed. `CTransition::step_up` @0x0050b610
|
||||
(`acclient_2013_pseudo_c.txt:273109-273117`):
|
||||
|
||||
```
|
||||
0050b655 float step_up_height = 0.0399999991f; // fallback
|
||||
0050b661 if ((this->object_info.state & 2) != 0) { // <- the gate
|
||||
0050b665 OBJECTINFO::get_walkable_z(this);
|
||||
0050b671 step_up_height = this->object_info.step_up_height; // authored
|
||||
}
|
||||
0050b6ba CTransition::step_down(this, step_up_height, arg2)
|
||||
```
|
||||
|
||||
`step_down` has the same shape at `0x0050b852` (default `0.04`, conditional
|
||||
substitution) and reads the authored value unconditionally at `0x0050c232`,
|
||||
where it is then halved against the sphere radius if it exceeds a diameter.
|
||||
|
||||
**Two facts fall out of this, and the second is the more useful one.**
|
||||
|
||||
**(1) The fallback is `0.04`, not `0.4`.** Our value matches neither retail's
|
||||
fallback nor the authored `0.600`/`1.500`. It is an order of magnitude above
|
||||
retail's fallback and well below the authored value.
|
||||
|
||||
**(2) `state & 2` is `OnWalkable`** in our own `ObjectInfoState`. So retail
|
||||
applies the authored step height ONLY while standing on walkable ground, and
|
||||
drops to `0.04` otherwise. **We already port that gate correctly** —
|
||||
`Transition.DoStepUp` (`TransitionTypes.cs` ~5836) is a faithful copy,
|
||||
including `stepDownHeight = oi.StepUpHeight`, which reads oddly but is exactly
|
||||
what retail passes. **The gate is not the defect. Only the VALUE fed into it
|
||||
is.**
|
||||
|
||||
### Where the 0.4 comes from — mapped, with one hop unproven
|
||||
|
||||
- `PlayerMovementController._stepUpHeight` / `_stepDownHeight` are
|
||||
**initialised to `0.4f`** (`PlayerMovementController.cs:159-160`).
|
||||
- The `StepUpHeight` property's own doc comment says the authoritative source
|
||||
is the player's `Setup.StepUpHeight`, set by
|
||||
**`PlayerModeController.ApplyStepHeights`**. **That method does not exist
|
||||
anywhere in the tree** — the identifier appears exactly once, inside that
|
||||
comment. Either the wiring was removed and the comment survived, or it never
|
||||
landed.
|
||||
- **Remotes and live entities are NOT affected.** They get Setup-derived
|
||||
values: `LiveEntityMotionRuntimeController.cs:321`
|
||||
(`setup.StepUpHeight * scale`, falling back to `0.4f`) and
|
||||
`RuntimeSetPositionMoverPreparation.cs:180`. The local player is the odd one
|
||||
out — which is the population that matters, since it is what the user feels.
|
||||
|
||||
**NOT ESTABLISHED, and must be before any fix.** There IS one real writer:
|
||||
`RuntimeLocalPlayerPhysicsPublicationState.cs:215-216` assigns from
|
||||
`command.Physics.StepUpHeight`, and that command is built by
|
||||
`RuntimeSetPositionMoverPreparation` — which *does* compute the Setup-derived
|
||||
value. So the plumbing exists. Whether it runs for the local player, or runs
|
||||
and is then overwritten, is unproven; the live probe reading `0.400` says the
|
||||
controller held its default at that moment, not why. **Print the controller's
|
||||
two values at world entry and at the first resolve before changing anything.**
|
||||
A fix that sets the field without knowing which path won will be a coin flip.
|
||||
|
||||
### Remaining open question
|
||||
|
||||
- Whether the authored Setup values are what retail feeds `CPhysicsObj`, or
|
||||
whether retail also substitutes constants at this seam. **Grep
|
||||
`named-retail` for `get_stepup_height` / `get_stepdown_height` and their
|
||||
callers before touching anything** — the authored DAT field being ignored is
|
||||
only a defect if retail reads it.
|
||||
- Where the 0.400 comes from: a hardcoded default, a stance/posture-dependent
|
||||
value, or a value that never got wired from the Setup.
|
||||
- Whether it has any observable consequence. Do not open this by reasoning
|
||||
from the source; the #337 lineage already burned two diagnoses that way.
|
||||
|
||||
### Related
|
||||
|
||||
Sits next to #32 (local-player cliff edge-slide), which has its own research
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue