Commit graph

15 commits

Author SHA1 Message Date
Erik
d94145e6b8 fix(physics): seal collision generations before activation 2026-07-31 15:53:05 +02:00
Erik
be94bc9b06 fix(physics): activate collision generations atomically 2026-07-31 15:19:25 +02:00
Erik
dae5b1ea68 fix(physics): TS-46 - seed the sweep from the Setup's own sphere list
Campaign P Slice P3 item 1. Retail CPhysicsObj::transition (0x00512dc0)
seeds the collision sweep from CPartArray::GetSphere (the Setup's own
<=2-sphere list, each origin+radius scaled by m_scale) via
SPHEREPATH::init_sphere (0x0050c670) -- not from a symmetric two-scalar
(radius, height) capsule reconstruction. The human Setup 0x02000001's
authored spheres are (0,0,0.475) r=.48 and (0,0,1.350) r=.48; the old
reconstruction from (0.48, 1.835) produced (0,0,0.48) + (0,0,1.355), a
5 mm head-center offset the TS-46 register row documented as a residual.

Port:
- SpherePath.InitPath gains a sphere-list overload (ImmutableArray<
  FlatCollisionSphere>, scale) sharing a new InitPathCore with the
  existing (radius, height) overload, which is now the degenerate
  2-scalar case of the same code -- byte-for-byte unchanged, so every
  captured-fixture replay (CellarUpTrajectoryReplayTests,
  DoorBugTrajectoryReplayTests, CellarLipWedgeTests) keeps passing
  unmodified.
- PhysicsEngine.ResolveWithTransition gains optional sphereList/
  sphereScale parameters; empty/default preserves the legacy scalar
  path for every pre-existing caller.
- LiveEntityMotionRuntimeController.GetSetupMoverShape is a new sibling
  of GetSetupCylinder (left untouched) that resolves the Setup's own
  sphere list plus Setup-derived step-up/step-down
  (CPartArray::GetStepUpHeight/GetStepDownHeight, 0x005180d0/0x005180f0,
  x ObjScale, 0.4 m fallback matching the pre-existing literal).
- Threaded through PlayerMovementController (both resolve call sites,
  new SphereList property set by PlayerModeController.ApplyStepHeights
  and the Headless world projection), RuntimeRemotePhysicsUpdater
  (Tick + TickHidden), and RuntimeOrdinaryPhysicsUpdater.TryBegin.
  Remote/ordinary step heights are now Setup-derived instead of a
  hardcoded 0.4f literal. Projectile and camera-probe sweeps are
  untouched (already single-sphere-exact).
- PlayerModeController.ApplyStepHeights also now applies the x ObjScale
  multiply to the player's own step heights (previously only the
  remote/ordinary paths did), closing an adjacent gap the P3 research
  flagged.

Ts46SphereListConformanceTests proves the sphere-list overload sees the
exact dat spheres (not the reconstruction), that the scalar overload is
unchanged, and that ResolveWithTransition's sphereList parameter
actually drives the sweep (a decoy-scalar control pair using a
head-height obstacle sphere).

Register: TS-46 retired (both residuals it named are closed); header
count corrected to 40 active TS rows.

dotnet build + dotnet test (Core.Tests 3991/2 skip, Runtime.Tests
425/0, App.Tests 3968/3 skip, complete solution build) all green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 09:05:44 +02:00
Erik
9355ddcec6 feat(physics): Campaign P P1 - stat-coupled movement (burden/stamina/vitae)
Ports the retail CACQualities/EncumbranceSystem/MovementSystem chain
(named-retail decomp pc 256393/412901-414050/416169-416320/695958+) so
PlayerWeenie's run rate, jump height, jump permission, and jump stamina
cost are real functions of burden, current stamina, and vitae/skill
enchantments instead of stubs.

Core:
- New EncumbranceSystem.cs (delegates to the already-verified
  BurdenMath formulas — one source of truth for the burden HUD and
  movement physics) and MovementSystem.cs (GetRunRate/GetJumpHeight/
  JumpStaminaCost/GetJumpPower, decomp-cited; ACE cross-referenced
  where BN dropped the general-case arithmetic entirely).
- PlayerWeenie rewritten as the CACQualities-shaped composition:
  CanJump gates on burden (<2.0 load, UN-8 — x87 polarity resolved by
  plausibility, Ghidra MCP unavailable this slice), JumpStaminaCost
  returns the real ceil((load+0.5)*power*8+2) cost and always affords
  it (matches decomp — retail's own function never refuses; "weak"
  jump comes entirely from the stamina==0 skill-zeroing gate inside
  InqRunRate/InqJumpVelocity, not a hard refusal), SetStamina wires a
  null="unknown, don't gate" sentinel preserving every pre-P1 test.
- EnchantmentMath.GetMod gained an optional StatModType flag filter
  (GetSkillMod convenience wrapper) so the SAME vitae/family-stacking
  machinery already used for vital-max buffs now also answers "what's
  the vitae+skill-enchantment-adjusted Run/Jump skill" — reusing the
  M3 active-enchantment state, not a new engine.

Runtime:
- RuntimeCharacterState now stores the pre-EnchantSkill base run/jump
  skill and recomputes the adjusted value (vitae first, then matching
  Skill-flagged buffs, floor 0.5, truncate) on every base push AND on
  every Spellbook.EnchantmentsChanged notification — a vitae change
  alone moves the produced rate without a fresh PlayerDescription.
- RuntimeMovementSkillState extended with Burden/CurrentStamina
  (RuntimeMovementSkillProjection.ApplyTo pushes both through the
  existing seam); LiveSessionEventRouter recomputes burden from the
  same Strength+aug-property+EncumbranceVal inputs the burden HUD
  already assembles (reacting to the same ClientObjectTable events)
  and pushes current stamina from LocalPlayerState vital updates.
- Wires the previously dead-lettered ReportExhaustion() R3-W4 seam:
  LiveSessionRuntimeFactory's OnMovementStatsUpdated callback re-
  applies the current snapshot to the live controller and forces an
  immediate movement re-evaluation on any skill/burden/stamina change.

Register: retires TS-5 (CanJump/JumpStaminaCost stubs) and AP-25 (no
vitae in pushed skill). Adds AP-127 (two minor unmodeled retail bonus
properties + the stamina-buff-adjusts-local-copy nuance, deliberately
out of the bounded "run/jump query path only" scope) and UN-8 (the
CanJump x87 polarity call, flagged for a future Ghidra MCP
confirmation pass). Extends TS-23 (PlayerKillerStatus not parsed) to
cover JumpStaminaCost's new pk parameter, hardcoded false pending P3.

Full pseudocode + retail citations + the vitae/skill-level finding in
docs/research/2026-07-30-stat-coupled-movement-pseudocode.md.

Release suite: Core.Tests 3977/2 skips, Runtime.Tests 425/0 skips,
App.Tests 3968/3 skips — all green. (One pre-existing, unrelated Debug-
only flake in LandblockBuildOriginTests reproduces on the pre-P1
baseline and passes in Release; not touched here.)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 08:18:06 +02:00
Erik
66f114b258 feat(linux): add graphical platform services 2026-07-27 11:54:59 +02:00
Erik
776482da82 perf(headless): enforce K4 resource envelope 2026-07-27 11:14:50 +02:00
Erik
cb512fd091 perf(headless): establish K4 resource telemetry 2026-07-27 10:47:31 +02:00
Erik
3f3401257c fix(headless): complete connected movement gate 2026-07-27 10:26:44 +02:00
Erik
b6547ff38c feat(headless): hydrate isolated collision worlds 2026-07-27 09:25:58 +02:00
Erik
9569dadb57 feat(headless): share immutable gameplay content 2026-07-27 09:00:48 +02:00
Erik
12b500d383 feat(headless): share immutable process content 2026-07-27 08:37:24 +02:00
Erik
38e83640d9 feat(headless): complete deterministic bot command parity 2026-07-27 08:23:36 +02:00
Erik
7e8acb74dd feat(headless): add deterministic multi-session scheduler 2026-07-27 07:51:49 +02:00
Erik
f8cb840fb1 feat(headless): complete portable single-session host 2026-07-27 07:36:53 +02:00
Erik
aada8a37c1 feat(headless): establish portable Linux host boundary
Add the presentation-free acdream-headless executable, strict no-connect configuration validation, dependency and assembly guards, and a Windows/Ubuntu CI lane that builds and tests only the portable runtime closure.

Co-authored-by: Codex <noreply@openai.com>
2026-07-27 01:10:45 +02:00