Files
Project-M/Docs/Vault/07_Sessions/2026/2026-06-01_M5b_Character_Controller.md
T
2026-06-02 08:56:26 -07:00

5.7 KiB
Raw Blame History

date, type, tags, permalink
date type tags permalink
2026-06-01 session
session
dots
netcode
physics
character-controller
prediction
m5
gamevault/07-sessions/2026/2026-06-01-m5b-character-controller

Session 2026-06-01 — M5b: adopt the Unity Character Controller package

Goal

Operator decision: replace the M5 dynamic-Rigidbody player (DR-006_M5_Physics_In_Prediction) with Unity's Character Controller package (kinematic, collide-and-slide, DOTS, netcode-predicted) as the player's movement foundation. Run via /dots-dev with a multi-agent research workflow. Architecture locked in DR-007_M5b_Character_Controller_Package.

Process

  • Read-only research workflow (6 parallel Explore agents → synthesis): compatibility (two angles), CC netcode setup, CC core API, codebase impact. Returned a unified plan + a hard compatibility verdict.
  • Compatibility gate (the make-or-break): research said CC 1.4.2 declares entities/physics@1.3.15 vs our Entities 6.4.0 (Unity-6 renumber) — likely incompatible. Resolved by an empirical install probe (operator-gated): added the package, confirmed the lock kept Entities 6.4.0 / Physics 1.4.6 / Netcode 1.13.2 (no downgrade) and compiled clean. The floors were satisfied → it works. Probe → pause → operator "go".
  • Port: a sub-agent fetched the OnlineFPS netcode-character sample verbatim; I reconciled its API against the installed 1.4.2 via unity_reflect (the canonical path is IKinematicCharacterProcessor<T> + KinematicCharacterDataAccess + static KinematicCharacterUtilities.Update_*; the legacy KinematicCharacterAspect also exists but isn't what the samples use). Authored a minimal top-down adaptation.

Done

  • New (ProjectM.Simulation): CharacterComponent + CharacterControl (CharacterComponents.cs); CharacterControlMath.DesiredMovement (unit-test seam); CharacterProcessor (the IKinematicCharacterProcessor running the Update_* sequence, gravity-free, velocity-controlled); CharacterPhysicsUpdateSystem (KinematicCharacterPhysicsUpdateGroup); PlayerControlSystem (PlayerInput × MoveSpeed → CharacterControl); CharacterGhostVariants (CharacterInterpolation → PredictedClient-only).
  • New (ProjectM.Authoring): PlayerCharacterAuthoring — baker calls KinematicCharacterUtilities.BakeCharacter (top-down props) + adds CharacterComponent/CharacterControl.
  • Modified: ProjectM.Simulation.asmdef + ProjectM.Authoring.asmdef (+Unity.CharacterController, Authoring +Unity.Physics); Player.prefab (removed M5 Rigidbody, kept CapsuleCollider, added PlayerCharacterAuthoring, scale 1); StatRecomputeSystem (dropped the now-dangling [UpdateBefore(PlayerMoveSystem)]).
  • Deleted: PlayerMoveSystem, PlayerPlanarConstraintSystem (CC + no-gravity stays planar — no constraint needed); PlayerMoveSystemTestsCharacterControlMathTests.
  • Kept: PlayerInput + input gather + DebugInputInjectionSystem, EffectiveCharacterStats/StatRecompute, GhostOwner/spawn/co-op ring, PlayerAimSystem, combat/health, the NetCodePhysicsConfig + baked static walls from DR-006.

Validation

  • EditMode 47/47 green (4 new CharacterControlMath tests replace the 4 old PhysicsVelocity-mapping tests).
  • Runtime (single in-editor client, 6.4.7): player bakes the full CC set (KinematicCharacterBody/Properties, PhysicsCollider, CharacterControl, CharacterComponent, CharacterInterpolation, the 4 CC buffers) on both worlds; spawns at the ring slot (2.5,1,0). Driving +X stops the capsule at x=5.24 (= Wall_East face radius) on server and client; diagonal input slides along the wall and rounds its finite end (collide-and-slide, no tunnel); Y holds 1.00 with no planar-pin system; server == client. CharacterInterpolation confirmed on the client ghost, absent on the server (predicted-only variant works). Console clean of CC/Burst/cascade signatures — only the known unfocused-editor tick-batching artifact.

Decisions

  • DR-007_M5b_Character_Controller_Package — CC 1.4.2 resolves on our stack (SemVer floors, no downgrade); kinematic collide-and-slide owner-predicted character via the static-utilities pattern; data-driven velocity from existing PlayerInput/stats; CharacterInterpolation predicted-only; do NOT globally DontSerialize LocalTransform (protects non-character ghosts); supersedes the DR-006 dynamic-Rigidbody mover, keeps the DR-006 predicted-physics infra.

Diagnosis notes (for future me)

  • The compatibility "no" was a false alarm — a package declaring an older entities@1.3.x dependency still resolves against the renumbered Entities 6.4.0 (SemVer floor); always probe rather than trust the version-string mismatch. Verify the lock didn't downgrade + the package compiles.
  • Trust unity_reflect over sub-agent package-cache reads for the installed API shape: reflect showed both the aspect (legacy) and the static-utilities path; the samples use the latter, which compiled first-try.
  • Continued to edit Assets .cs exclusively via MCP create_script/apply_text_edits (see 2026-06-01_M5_Physics_In_Prediction / the Write-tool stale-assembly trap).

Open / deferred

  • Multi-client co-op interpolation — validate remote-peer smoothness with a live two-build / thin-client run (predicted-only CharacterInterpolation variant is in place; single-client validated).
  • Player-vs-player non-physical (SimulateDynamicBody=false); gravity-free/no floor (planar); CC declares older deps (revisit on CC bump); optional KinematicCharacterBody velocity ghost variant for tighter reconciliation under latency.

Next

Recommend a real two-build LAN co-op smoke test (also closes the M4 deferral) to validate remote CC interpolation, then resume the base subscene streaming half of M5.