Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb122d52a9 | |||
| e819eeb35b | |||
| 8776a6b362 | |||
| c3094c9413 | |||
| 7d5d13f702 | |||
| 742c415885 | |||
| 8c71e46872 |
@@ -0,0 +1,135 @@
|
||||
# M02-GMP-INPUT-PROFILE-335-001 — WoW 3.3.5a input profile
|
||||
|
||||
<!-- OPENWC_CLAIM:M02-GMP-INPUT-PROFILE-335-001:sindo-main-codex:2026-07-17 -->
|
||||
|
||||
## Ownership
|
||||
|
||||
- Target: M02
|
||||
- Program: GMP/QAR
|
||||
- Owner/Agent ID: sindo-main-codex
|
||||
- Branch: `work/sindo-main-codex/m02-input-profile-335`
|
||||
- Lease expires UTC: 2026-07-17
|
||||
- Integrator: M02 milestone integrator
|
||||
|
||||
## Outcome
|
||||
|
||||
Add a profile-aware, remappable `Blizzlike335` input path whose default movement
|
||||
bindings match the extracted build-12340 binding table while preserving the
|
||||
existing `RenderSandbox` controls. Add deterministic turn intent and keyboard
|
||||
turn consumption at the server-contract default turn rate.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Implement jump/fall/swim, network prediction or server reconciliation.
|
||||
- Claim complete movement or camera parity from binding and turn-rate evidence.
|
||||
- Persist user keybindings or build keybinding UI.
|
||||
- Commit proprietary extracted client files.
|
||||
- Mark M02 complete or edit its checklist/Evidence.
|
||||
|
||||
## Paths
|
||||
|
||||
- Exclusive: `src/tests/fixtures/player_input_profile_335.json`, this claim
|
||||
- Shared/hotspots: `project.godot`, `src/domain/input/move_intent.gd`,
|
||||
`src/gameplay/input/player_input_actions.gd`,
|
||||
`src/gameplay/input/player_input_source.gd`,
|
||||
`src/gameplay/movement/local_player_movement_controller.gd`,
|
||||
`src/scenes/player/third_person_wow_controller.gd`,
|
||||
`src/scenes/player/third_person_camera_rig.gd`, player/movement verifiers
|
||||
and regression scene, `docs/modules/player-input.md`,
|
||||
`docs/modules/local-player-movement.md`, `docs/modules/third-person-camera.md`
|
||||
- Generated/ignored: local `.godot`, native DLL and proprietary extracted corpus
|
||||
|
||||
## Contracts and data
|
||||
|
||||
- `MoveIntent` gains an immutable, clamped signed turn axis.
|
||||
- `PlayerInputSource` selects explicit sandbox or compatibility action sets at
|
||||
construction and routes compatibility A/D to strafe while camera rotation is held.
|
||||
- `LocalPlayerMovementController` converts turn intent into a deterministic yaw
|
||||
delta without reading engine input or owning a scene transform.
|
||||
- A sanitized JSON fixture records selected binding facts, source hashes and the
|
||||
pinned TrinityCore 3.3.5 server-contract commit.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Requires: merged sandbox capability package on master `c3094c9`.
|
||||
- Blocks: final M02 integration audit and milestone closeout.
|
||||
- External state: local extracted build-12340 binding files are evidence inputs
|
||||
only; committed tests are reproducible without them.
|
||||
|
||||
## Verification
|
||||
|
||||
- Fixture schema/provenance and selected default-binding regression.
|
||||
- Pure profile composition, A/D turn, Q/E strafe and camera-held A/D strafe cases.
|
||||
- Deterministic turn-rate and controller integration regression.
|
||||
- Existing M02 and repository gates remain required.
|
||||
|
||||
## Documentation deliverables
|
||||
|
||||
- Updated input/movement public API, profile matrix, data flow, sequence,
|
||||
failure/recovery, fidelity provenance and source maps.
|
||||
|
||||
## Simplicity and naming
|
||||
|
||||
- Important names: `turn_axis`, `BLIZZLIKE_STRAFE_LEFT`, `TURN_LEFT`.
|
||||
- Simplest approach: one profile selection at composition plus one scalar intent.
|
||||
- Rejected complexity: input-context framework, command bus and persisted binding store.
|
||||
- Unavoidable complexity: compatibility A/D behavior depends on camera-rotate state.
|
||||
- Measured optimization evidence: not applicable.
|
||||
|
||||
## Status
|
||||
|
||||
- State: ready-for-review
|
||||
- Done: added distinct remappable profiles, signed turn intent/controller path,
|
||||
camera-yaw synchronization, sanitized provenance fixture, regression coverage
|
||||
and updated module specifications
|
||||
- Next: milestone integrator reviews and merges `8776a6b`
|
||||
- Blocked by:
|
||||
|
||||
<!-- OPENWC_HANDOFF:READY:M02-GMP-INPUT-PROFILE-335-001:8776a6b -->
|
||||
|
||||
## Handoff
|
||||
|
||||
- Branch/commit: `work/sindo-main-codex/m02-input-profile-335` at `8776a6b`.
|
||||
- Outcome: `RenderSandbox` retains A/D strafe and debug E/Q/Space/Shift behavior;
|
||||
`Blizzlike335` now samples W/S and Up/Down forward/back, Q/E strafe, A/D and
|
||||
Left/Right turn, with A/D routed to strafe while right-mouse rotation is active.
|
||||
- Public contracts: `MoveIntent.turn_axis`; profile-selecting
|
||||
`PlayerInputSource.new(profile_id)`; pure compatibility composition;
|
||||
`LocalPlayerMovementController.calculate_yaw_delta_radians(...)`; camera yaw
|
||||
synchronization after keyboard turn. Unknown input profiles fail closed to
|
||||
`Blizzlike335`.
|
||||
- Project configuration: four additive compatibility actions; existing action
|
||||
names and sandbox mappings remain valid. W/S also gain the original Up/Down
|
||||
secondary defaults.
|
||||
- Verification: player input `actions=16 intent_cases=9 profiles=3 fixture=1
|
||||
controller=1 regression_scene=3`; movement `cases=15 state_transitions=2`;
|
||||
capabilities `profiles=3 sprint=2 flight=2 scenes=2`; terrain
|
||||
`contract=4 interpolation=1 cache=1 failures=2`; camera
|
||||
`state_cases=12 policy_cases=3`; presentation `appearance_cases=9
|
||||
animation_cases=10`; coordinate boundaries `files=101`; StreamingFocus
|
||||
`runtime_scenes=2 capture_tools=3`.
|
||||
- Renderer: unified dry-run passed project/material/dedupe/cache/manifest/
|
||||
calibration/coordinate/server-spawn gates and planned all seven checkpoints;
|
||||
coordinate gate reported `files=103`. Missing proprietary GLB/DBC/ADT inputs
|
||||
produced the expected diagnostics only.
|
||||
- Repository gates: documentation `module_specs=8`; coordination
|
||||
`fallback_claims=31`, with the same five unrelated expired M00 warnings.
|
||||
- Fidelity: local build-12340 `DefaultBindings.wtf` SHA-256
|
||||
`35FFA0E4E2356A13A0633A848F9E57ABE7DF9D8A16C2245E15D33013AD2F56A5`
|
||||
and `Bindings.xml` SHA-256
|
||||
`2E01276AFB7462F1417710F13B4BF1A456341F7F28CC8AE0D6D9C7442D7F6793`
|
||||
were rechecked and selected facts sanitized into the committed fixture.
|
||||
TrinityCore revision `2853a621d6af91a803787a2b8a509f4ce3e0300d` supplies the
|
||||
3.141594 rad/s player server-contract turn rate. WoWee revision
|
||||
`626243e937fb93965fa583a6507ed5a1aa7dda4b` supports right-mouse A/D routing.
|
||||
- Fidelity limits: server turn rate and public reference routing are not direct
|
||||
original-client timing/behavior proof. Jump, autorun and left-button
|
||||
camera/select defaults are recorded but not implemented. This package does
|
||||
not claim complete input, movement or camera parity.
|
||||
- Migration/cache: no persisted settings or cache schema. Future saved bindings
|
||||
must migrate stable action names; current project users receive additive actions.
|
||||
- Documentation: updated input, movement and camera APIs, inputs/outputs, data
|
||||
flow, sequence, ownership, failure/recovery, configuration, fidelity and source maps.
|
||||
- Recommended merge order: merge after sandbox capabilities (already on master),
|
||||
then run the final M02 integration/evidence audit without marking the target
|
||||
done solely from this package.
|
||||
@@ -0,0 +1,126 @@
|
||||
# M02-GMP-SANDBOX-CAPABILITIES-001 — Debug movement capability gate
|
||||
|
||||
<!-- OPENWC_CLAIM:M02-GMP-SANDBOX-CAPABILITIES-001:sindo-main-codex:2026-07-16 -->
|
||||
|
||||
## Ownership
|
||||
|
||||
- Target: M02
|
||||
- Program: GMP/FND
|
||||
- Owner/Agent ID: sindo-main-codex
|
||||
- Branch: `work/sindo-main-codex/m02-sandbox-capabilities`
|
||||
- Lease expires UTC: 2026-07-16
|
||||
- Integrator: M02 milestone integrator
|
||||
|
||||
## Outcome
|
||||
|
||||
Introduce an immutable local-player movement capability contract and require it
|
||||
at the movement boundary so debug sprint and free flight execute only in the
|
||||
explicit `RenderSandbox` profile and are rejected by `Blizzlike335`.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Claim that current movement values or `Blizzlike335` locomotion are 1:1.
|
||||
- Build a global application/profile framework before the application shell exists.
|
||||
- Remove debug Input Map actions or change their current sandbox bindings.
|
||||
- Implement jump, fall, swim, collision, server authority or reconciliation.
|
||||
- Mark M02 complete or edit its checklist/Evidence.
|
||||
|
||||
## Paths
|
||||
|
||||
- Exclusive: `src/gameplay/movement/player_movement_capabilities.gd`,
|
||||
`src/tools/verify_player_movement_capabilities.gd`, this claim
|
||||
- Shared/hotspots: `src/gameplay/movement/local_player_movement_controller.gd`,
|
||||
`src/scenes/player/third_person_wow_controller.gd`, movement/input verifiers,
|
||||
player regression scene, `docs/modules/local-player-movement.md`,
|
||||
`docs/modules/player-input.md`
|
||||
- Generated/ignored: local `.godot`, native DLL, generated resources and renderer corpus
|
||||
|
||||
## Contracts and data
|
||||
|
||||
- `PlayerMovementCapabilities` owns immutable profile ID plus explicit debug
|
||||
sprint/flight booleans and safe named factories.
|
||||
- `LocalPlayerMovementController` requires the capability value; missing input
|
||||
falls back to `Blizzlike335`, never sandbox.
|
||||
- Player scene maps its exported profile selection once at the composition boundary.
|
||||
- Input actions and `MoveIntent` remain unchanged; rejected debug requests have no effect.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Requires: merged character presentation package on master `8c71e46`.
|
||||
- Blocks: final M02 integration audit and milestone closeout.
|
||||
- External state: none; verification is asset-free.
|
||||
|
||||
## Verification
|
||||
|
||||
- Pure profile factory/default and immutability regression.
|
||||
- Sprint accepted in RenderSandbox and ignored in Blizzlike335.
|
||||
- Flight toggle/vertical basis accepted in RenderSandbox and rejected in Blizzlike335.
|
||||
- Real regression scene verifies both profile compositions.
|
||||
- Existing input/movement/terrain/camera/presentation and renderer gates remain required.
|
||||
- Fidelity evidence: negative proof that debug capabilities cannot affect the
|
||||
compatibility profile; no positive movement parity claim.
|
||||
|
||||
## Documentation deliverables
|
||||
|
||||
- Inline public API and profile semantics on the capability/controller boundary.
|
||||
- Updated movement and input specs: API, inputs/outputs, data flow, lifecycle,
|
||||
failure/recovery, capability matrix and source map.
|
||||
|
||||
## Simplicity and naming
|
||||
|
||||
- Important name: `PlayerMovementCapabilities`.
|
||||
- Simplest approach: one immutable value injected into the existing controller.
|
||||
- Rejected complexity: autoload singleton, generic feature-flag service and global profile registry.
|
||||
- Unavoidable complexity: one profile-to-capability mapping at scene composition.
|
||||
- Measured optimization evidence: not applicable.
|
||||
|
||||
## Status
|
||||
|
||||
- State: ready-for-review
|
||||
- Done: added immutable capability contract, gated sprint/free-flight, covered
|
||||
pure and real-scene profiles and updated movement/input specifications
|
||||
- Next: milestone integrator reviews and merges `742c415`
|
||||
- Blocked by:
|
||||
|
||||
<!-- OPENWC_HANDOFF:READY:M02-GMP-SANDBOX-CAPABILITIES-001:742c415 -->
|
||||
|
||||
## Handoff
|
||||
|
||||
- Branch/commit: `work/sindo-main-codex/m02-sandbox-capabilities` at `742c415`.
|
||||
- Outcome: debug sprint and free flight now require explicit
|
||||
`PlayerMovementCapabilities.render_sandbox()`; `Blizzlike335`, unknown and
|
||||
null capability inputs reject both effects.
|
||||
- Public contract: immutable profile ID plus `allows_debug_sprint` and
|
||||
`allows_debug_free_flight`; named factories map configuration once at the
|
||||
composition boundary. The movement controller exposes its effective profile ID.
|
||||
- Runtime composition: `ThirdPersonWowController.movement_profile_id` defaults
|
||||
to `RenderSandbox`, preserving renderer-scene behavior. Selecting
|
||||
`Blizzlike335` keeps ordinary movement while ignoring Shift/Space/E/Q effects.
|
||||
- Verification: capability `profiles=3 sprint=2 flight=2 scenes=2 boundary=1`,
|
||||
movement `cases=12 state_transitions=2`, input `actions=12 intent_cases=6`,
|
||||
terrain `contract=4 interpolation=1 cache=1 failures=2`, camera
|
||||
`state_cases=12 policy_cases=3`, presentation
|
||||
`appearance_cases=9 animation_cases=10`, coordinate boundaries
|
||||
`files=101 consumers=5`, and StreamingFocus `runtime_scenes=2 capture_tools=3` passed.
|
||||
- Renderer: dry-run passed project/material/dedupe/cache/manifest/calibration/
|
||||
coordinate/server-spawn gates and planned all seven checkpoints; the combined
|
||||
run reported coordinate `files=103`. Missing proprietary GLB/DBC/ADT inputs
|
||||
produced the expected diagnostics only.
|
||||
- Repository gates: documentation `module_specs=8`, coordination
|
||||
`fallback_claims=30`; five unrelated expired M00 claim warnings remain.
|
||||
- Fidelity: this package provides negative evidence that sandbox-only debug
|
||||
movement cannot alter the `Blizzlike335` profile. It does not prove ordinary
|
||||
movement, bindings, flight or timing match build 12340.
|
||||
- Migration: direct `LocalPlayerMovementController.new(...)` callers that need
|
||||
debug behavior must now pass `render_sandbox()`; omitted/null capability is
|
||||
intentionally compatibility-safe. Existing repository scenes require no edit.
|
||||
- Cache/persistence: no schema, cache, binding or stored-profile migration.
|
||||
- Local ignored inputs: native extension DLL, UID cache and generated ADT
|
||||
resource scripts supported renderer verification and are not committed.
|
||||
- Risks: runtime renderer scenes still default to `RenderSandbox`; the future
|
||||
application shell must explicitly choose its profile. `Blizzlike335` currently
|
||||
guarantees only debug exclusion, not complete movement fidelity.
|
||||
- Recommended merge order: merge after presentation (already on master), then
|
||||
perform the final M02 integration/evidence audit before any target closeout.
|
||||
- Documentation: updated movement/input API, inputs/outputs, data flow, state,
|
||||
sequence, ownership, failure/recovery, capabilities, verification and source maps.
|
||||
@@ -5,17 +5,18 @@
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Status | Implemented |
|
||||
| Target/work package | M02 / M02-GMP-MOVEMENT-001, camera basis and character-presentation consumer updates |
|
||||
| Target/work package | M02 / M02-GMP-MOVEMENT-001, M02-GMP-SANDBOX-CAPABILITIES-001, M02-GMP-INPUT-PROFILE-335-001 and presentation consumers |
|
||||
| Owners | Gameplay local movement state; scene composition owns the instance |
|
||||
| Last verified | `97bb53f`, 2026-07-14 |
|
||||
| Profiles/capabilities | Current render sandbox; production/debug profile gate pending |
|
||||
| Last verified | M02-GMP-INPUT-PROFILE-335-001 worktree, 2026-07-15 |
|
||||
| Profiles/capabilities | `RenderSandbox` debug movement; `Blizzlike335` selected bindings and keyboard turn with debug sprint/flight rejected |
|
||||
|
||||
## Purpose
|
||||
|
||||
Own current local velocity, acceleration and sandbox flight state independently
|
||||
of the player scene. Convert an immutable `MoveIntent` plus an explicit
|
||||
Godot-world movement basis into deterministic per-tick displacement without
|
||||
querying terrain, cameras, input devices or visual assets.
|
||||
Godot-world movement basis into deterministic per-tick displacement and convert
|
||||
signed turn intent into a yaw delta without querying terrain, cameras, input
|
||||
devices or visual assets.
|
||||
|
||||
## Non-goals
|
||||
|
||||
@@ -32,7 +33,10 @@ flowchart LR
|
||||
Input[MoveIntent] --> Movement[LocalPlayerMovementController]
|
||||
Basis[Explicit local movement Basis] --> Movement
|
||||
Delta[Physics delta seconds] --> Movement
|
||||
Profile[Scene profile ID] --> Capabilities[PlayerMovementCapabilities]
|
||||
Capabilities --> Movement
|
||||
Movement --> Displacement[Godot-world displacement]
|
||||
Movement --> Yaw[Godot yaw delta radians]
|
||||
Movement --> Velocity[Read-only velocity state]
|
||||
Scene[ThirdPersonWowController] --> Basis
|
||||
Displacement --> Scene
|
||||
@@ -57,11 +61,16 @@ Forbidden dependencies:
|
||||
|
||||
| Symbol | Kind | Purpose | Thread/lifetime | Errors |
|
||||
|---|---|---|---|---|
|
||||
| `LocalPlayerMovementController.new(...)` | Constructor | Sets explicit speeds, acceleration and sandbox sprint multiplier | Created by composition root; retained for player scene lifetime | Caller owns configuration validation |
|
||||
| `PlayerMovementCapabilities.render_sandbox()` | Factory | Creates the only debug sprint/free-flight capability set | Immutable caller value | None |
|
||||
| `PlayerMovementCapabilities.blizzlike_335()` | Factory | Creates the compatibility-safe set with debug movement disabled | Immutable caller value | Name is intent, not a parity claim |
|
||||
| `PlayerMovementCapabilities.for_profile_id(...)` | Factory | Maps composition configuration once; unknown IDs fail closed | Immutable caller value | Unknown maps to `Blizzlike335` |
|
||||
| `LocalPlayerMovementController.new(...)` | Constructor | Sets explicit speeds, acceleration, sprint multiplier and movement capabilities | Created by composition root; retained for player scene lifetime | Null capability defaults to `Blizzlike335` |
|
||||
| `godot_world_velocity_units_per_second` | Read-only state | Current Godot-world velocity after the last update | Stable until next mutation on owning thread | None |
|
||||
| `is_flight_enabled` | Read-only state | Current sandbox free-flight mode | Stable until toggle | None |
|
||||
| `toggle_sandbox_flight()` | Command | Toggles flight and clears velocity | Owning physics/input thread | Returns new flight state |
|
||||
| `movement_profile_id` | Read-only state | Effective capability profile ID | Controller lifetime | None |
|
||||
| `toggle_sandbox_flight()` | Command | Toggles flight only when explicitly permitted and clears velocity | Owning physics/input thread | Rejected request returns `false` with state unchanged |
|
||||
| `advance(move_intent, godot_world_movement_basis, delta_seconds)` | Stateful update | Accelerates toward requested velocity and returns displacement for the tick | Owning physics thread; one call per tick | Negative delta is treated as zero |
|
||||
| `calculate_yaw_delta_radians(move_intent, delta_seconds)` | Pure query | Converts signed turn input to Godot yaw delta | Owning physics thread | Negative delta is treated as zero |
|
||||
|
||||
Constructor units:
|
||||
|
||||
@@ -73,16 +82,19 @@ Constructor units:
|
||||
| `flight_vertical_speed_units_per_second` | Sandbox vertical Godot units per second |
|
||||
| `acceleration_units_per_second_squared` | Velocity change per second |
|
||||
| `sandbox_sprint_multiplier` | Dimensionless debug multiplier |
|
||||
| `keyboard_turn_speed_radians_per_second` | Positive keyboard yaw speed; defaults to PI rad/s |
|
||||
|
||||
## Inputs and outputs
|
||||
|
||||
| Direction | Contract/data | Producer | Consumer | Ownership | Thread/lifetime |
|
||||
|---|---|---|---|---|---|
|
||||
| Input | `MoveIntent` | `PlayerInputSource` | Movement controller | Immutable caller-held value | One physics tick |
|
||||
| Input | `PlayerMovementCapabilities` | Application/player scene composition | Movement controller | Immutable caller-held value | Controller lifetime |
|
||||
| Input | Godot-world `Basis` | Player or `ThirdPersonCameraRig` adapter | Movement controller | Value copy | One physics tick |
|
||||
| Input | Delta seconds | Godot physics loop | Movement controller | Scalar value | One physics tick |
|
||||
| Input | Flight toggle command | Remappable sandbox action via scene adapter | Movement controller | Synchronous command | Input event dispatch |
|
||||
| Output | Displacement `Vector3` | Movement controller | Player scene adapter | Value copy | Applied in same tick |
|
||||
| Output | Yaw delta radians | Movement controller | Player scene adapter | Scalar value | Applied before movement basis selection |
|
||||
| Output | Velocity `Vector3` | Movement controller | Facing and `CharacterAnimationPresenter` scene adapter | Read-only value copy | Until next update |
|
||||
| Output | Flight state | Movement controller | Basis/terrain scene adapter | Read-only boolean | Until next toggle |
|
||||
|
||||
@@ -97,9 +109,14 @@ Side effects:
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Intent[MoveIntent axes] --> Target[Calculate target velocity]
|
||||
Intent --> Turn[Calculate signed yaw delta]
|
||||
Turn --> SceneYaw[Scene applies character yaw]
|
||||
Basis[Player or camera-pivot Basis] --> Directions[Forward/right directions]
|
||||
Directions --> Target
|
||||
Config[Speeds and sprint multiplier] --> Target
|
||||
Profile[RenderSandbox or Blizzlike335] --> Capability[Immutable debug capabilities]
|
||||
Capability -->|allow or reject sprint| Target
|
||||
Capability -->|allow or reject flight toggle| Current
|
||||
Previous[Owned velocity] --> Integrate[move_toward by acceleration × delta]
|
||||
Target --> Integrate
|
||||
Integrate --> Current[Updated velocity]
|
||||
@@ -112,7 +129,8 @@ flowchart LR
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> GroundedSandbox
|
||||
GroundedSandbox --> FlyingSandbox: toggle / clear velocity
|
||||
GroundedSandbox --> FlyingSandbox: toggle [debug flight allowed] / clear velocity
|
||||
GroundedSandbox --> GroundedSandbox: toggle [debug flight rejected]
|
||||
FlyingSandbox --> GroundedSandbox: toggle / clear velocity
|
||||
GroundedSandbox --> GroundedSandbox: advance
|
||||
FlyingSandbox --> FlyingSandbox: advance
|
||||
@@ -128,8 +146,14 @@ sequenceDiagram
|
||||
participant Input as PlayerInputSource
|
||||
participant Scene as ThirdPersonWowController
|
||||
participant Move as LocalPlayerMovementController
|
||||
participant Cap as PlayerMovementCapabilities
|
||||
participant Present as CharacterAnimationPresenter adapter
|
||||
Input-->>Scene: MoveIntent
|
||||
Scene->>Cap: map configured profile once
|
||||
Scene->>Move: construct with immutable capabilities
|
||||
Scene->>Move: calculate_yaw_delta_radians(intent, delta)
|
||||
Move-->>Scene: yaw delta
|
||||
Scene->>Scene: apply yaw and synchronize camera orbit yaw
|
||||
Scene->>Move: advance(intent, selected basis, delta)
|
||||
Move-->>Scene: displacement
|
||||
Scene->>Scene: apply global position and ground snap
|
||||
@@ -140,6 +164,8 @@ sequenceDiagram
|
||||
## Ownership, threading and resources
|
||||
|
||||
- The player scene creates and exclusively owns one movement controller.
|
||||
- The composition root creates one immutable capability value; the controller
|
||||
retains it and exposes only its effective profile ID.
|
||||
- Velocity and flight state have the same lifetime as that controller.
|
||||
- All mutations currently occur on the main input/physics thread.
|
||||
- Read-only value returns are copies; consumers cannot mutate owned state.
|
||||
@@ -153,6 +179,8 @@ sequenceDiagram
|
||||
| Negative physics delta | `advance` guard | Returns zero displacement; velocity unchanged | Unit regression | Resume with valid non-negative delta |
|
||||
| Missing scene basis owner | Scene composition defect | Controller cannot be called correctly | Scene/parser error or boundary test | Restore explicit scene dependency |
|
||||
| Flight toggle during motion | Command path | Velocity clears before next step | State-transition regression | Continue from zero velocity |
|
||||
| Flight/sprint request in `Blizzlike335` | Capability check | Request has no effect | Profile regression | Select explicit `RenderSandbox` only for tooling/debug scenes |
|
||||
| Unknown/null profile capability | Factory/constructor safe default | Uses `Blizzlike335`; debug movement disabled | Capability regression | Correct composition profile ID |
|
||||
| Missing terrain data | `TerrainGroundSample.is_available == false` | Scene skips existing ground snap | Stable terrain failure code | Replace/recover query backend |
|
||||
|
||||
There is no asynchronous cancellation, retry or rollback. Recreating the
|
||||
@@ -169,6 +197,10 @@ controller resets velocity and flight state deterministically.
|
||||
| Flight vertical speed | `7.0` units/s | Sandbox debug | Fixed for controller lifetime | Vertical free-flight target |
|
||||
| Sprint multiplier | `6.0` | Sandbox debug | Fixed for controller lifetime | Multiplies planar and vertical targets |
|
||||
| Camera-relative basis | Selected only while flight is enabled | Sandbox debug | Per tick | Preserves existing pitched flight direction |
|
||||
| Debug sprint permission | Enabled | `RenderSandbox` only | Immutable | Allows sprint request multiplier |
|
||||
| Debug free-flight permission | Enabled | `RenderSandbox` only | Immutable | Allows toggle and vertical movement |
|
||||
| Compatibility-safe debug permissions | Disabled | `Blizzlike335` | Immutable | Ignores sprint/toggle requests |
|
||||
| Keyboard turn rate | `3.141594` rad/s | `Blizzlike335` composition | Fixed for controller lifetime | Server-contract default applied to signed turn intent |
|
||||
|
||||
## Persistence, cache and migration
|
||||
|
||||
@@ -187,13 +219,17 @@ separate versioned movement snapshot contract.
|
||||
|
||||
- Unit/contract: `src/tools/verify_local_player_movement.gd` covers forward,
|
||||
backward, strafe, rotated basis, acceleration, deceleration, sprint, flight,
|
||||
pitched camera basis, state reset and invalid delta.
|
||||
pitched camera basis, state reset, signed keyboard turn and invalid delta.
|
||||
- Capability: `verify_player_movement_capabilities.gd` covers three profile-ID
|
||||
cases, safe defaults, sprint/flight allow/reject behavior and two real scene compositions.
|
||||
- Boundary: verifier rejects Node/Input/Camera/ADT dependencies and movement
|
||||
integration/state remaining in the player scene.
|
||||
- Scene integration: `verify_player_input.gd` drives the asset-free player
|
||||
regression scene through forward motion and immediate flight toggle.
|
||||
- Fidelity evidence: default values and formulas are regression-locked against
|
||||
the pre-extraction sandbox. No original-client comparison is claimed.
|
||||
- Fidelity evidence: translation defaults remain regression-locked against the
|
||||
pre-extraction sandbox. The compatibility keyboard turn default is pinned to
|
||||
TrinityCore 3.3.5 `playerBaseMoveSpeed[MOVE_TURN_RATE]`; that server contract
|
||||
does not alone prove original-client timing parity.
|
||||
- Performance budget: constant-time vector math, no per-tick I/O or scene lookup;
|
||||
`MoveIntent` allocation remains owned by the input package.
|
||||
|
||||
@@ -202,7 +238,8 @@ separate versioned movement snapshot contract.
|
||||
- Terrain/collision policy can consume displacement without changing input or velocity ownership.
|
||||
- A future server-aware predictor may replace this controller behind the scene composition boundary.
|
||||
- A typed movement snapshot may expose deterministic replay state when M08/M09 require it.
|
||||
- Sandbox debug capability gating can reject sprint/flight before commands reach this controller.
|
||||
- A future application profile can map to this narrow capability value without
|
||||
coupling the movement controller to the application shell.
|
||||
|
||||
## Capability status
|
||||
|
||||
@@ -210,7 +247,9 @@ separate versioned movement snapshot contract.
|
||||
|---|---|---|---|
|
||||
| Scene-free local velocity state | Implemented | Pure controller and source boundary regression | Integrate target checklist after review |
|
||||
| Existing planar acceleration/speeds | Implemented | Exact numeric unit cases and real scene regression | Compare with build 12340 before fidelity claim |
|
||||
| Existing camera-relative free flight | Implemented | Pitched-basis and toggle/reset cases | Restrict to sandbox profile |
|
||||
| Compatibility keyboard turn | Implemented | Pinned server-core value, signed pure cases and real-scene profile regression | Direct original-client timing comparison remains required |
|
||||
| Existing camera-relative free flight | Implemented in `RenderSandbox` | Pitched-basis, profile and toggle/reset cases | Original-client flight semantics remain out of scope |
|
||||
| Typed sprint/free-flight exclusion | Implemented | Pure and real-scene profile regressions | Application shell must select profile explicitly later |
|
||||
| Terrain height query | Implemented | Typed `TerrainQuery` and injected player regression | Ground-snap policy remains scene-owned |
|
||||
| Terrain collision movement policy | Planned | Height-only query does not model collision | Add slopes/holes/collision later |
|
||||
| Jump/fall/swim | Planned | M02/M09 roadmap | Requires terrain/liquid and server contracts |
|
||||
@@ -218,12 +257,15 @@ separate versioned movement snapshot contract.
|
||||
|
||||
## Known gaps and risks
|
||||
|
||||
- Numeric defaults preserve the existing sandbox but are not original-client evidence.
|
||||
- Translation/acceleration defaults preserve the existing sandbox and are not original-client evidence.
|
||||
- Configuration is captured at scene `_ready`; runtime mutation of exported speed
|
||||
properties does not reconfigure an existing controller.
|
||||
- Ground snap remains in the player scene, but its ADT data access is now behind
|
||||
a replaceable `TerrainQuery`.
|
||||
- Sprint and free flight still lack a typed sandbox capability gate.
|
||||
- Runtime renderer scenes intentionally default to `RenderSandbox`; a future
|
||||
game-client composition must explicitly select `Blizzlike335`.
|
||||
- `Blizzlike335` currently means only debug movement exclusion and must not be
|
||||
interpreted as evidence that remaining movement semantics are 1:1.
|
||||
- The module uses Godot math value types; a future engine-independent gameplay
|
||||
predictor may require scalar/domain movement contracts.
|
||||
|
||||
@@ -232,13 +274,16 @@ separate versioned movement snapshot contract.
|
||||
| Path | Responsibility |
|
||||
|---|---|
|
||||
| `src/gameplay/movement/local_player_movement_controller.gd` | Owned velocity/flight state and deterministic integration |
|
||||
| `src/gameplay/movement/player_movement_capabilities.gd` | Immutable profile-to-debug-capability contract and safe defaults |
|
||||
| `src/gameplay/terrain/terrain_query.gd` | Replaceable ground-height input boundary |
|
||||
| `src/scenes/player/third_person_camera_rig.gd` | Camera-relative sandbox flight basis producer |
|
||||
| `src/scenes/character/character_animation_presenter.gd` | Locomotion presentation consumer behind the scene adapter |
|
||||
| `src/scenes/player/third_person_wow_controller.gd` | Composition, basis selection, displacement/terrain and presentation-state adapters |
|
||||
| `src/tools/verify_local_player_movement.gd` | Pure numeric, state-transition and dependency regression |
|
||||
| `src/tools/verify_player_movement_capabilities.gd` | Profile factory, allow/reject and real-scene regression |
|
||||
| `src/tests/scenes/player_input_regression.tscn` | Asset-free integrated player fixture |
|
||||
| `src/tools/verify_player_input.gd` | Input-to-movement scene regression |
|
||||
| `src/tests/fixtures/player_input_profile_335.json` | Turn-rate and selected binding provenance |
|
||||
|
||||
## Related decisions and references
|
||||
|
||||
|
||||
@@ -5,24 +5,25 @@
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Status | Partial |
|
||||
| Target/work package | M02 / M02-GMP-INPUT-001, M02-GMP-MOVEMENT-001 and M02-RND-CAMERA-001 consumer updates |
|
||||
| Target/work package | M02 / M02-GMP-INPUT-001, M02-GMP-SANDBOX-CAPABILITIES-001, M02-GMP-INPUT-PROFILE-335-001 |
|
||||
| Owners | Gameplay input boundary; `sindo-main-codex` for current package |
|
||||
| Last verified | `8c1cf9b`, 2026-07-14 |
|
||||
| Profiles/capabilities | Current render-sandbox defaults; `Blizzlike335` binding semantics not yet verified |
|
||||
| Last verified | M02-GMP-INPUT-PROFILE-335-001 worktree, 2026-07-15 |
|
||||
| Profiles/capabilities | Distinct RenderSandbox and Blizzlike335 action layouts; debug execution remains RenderSandbox-only |
|
||||
|
||||
## Purpose
|
||||
|
||||
Convert remappable Godot Input Map actions into an immutable, scene-free
|
||||
`MoveIntent` that can be consumed by the current player controller and a later
|
||||
independently testable local movement controller.
|
||||
`MoveIntent` that can be consumed by the independently testable local movement
|
||||
controller. Select either the preserved renderer-sandbox layout or the verified
|
||||
build-12340 movement bindings at the scene composition boundary.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Define authoritative server movement, prediction or reconciliation.
|
||||
- Own character transform, terrain queries, camera state or animation state.
|
||||
- Claim that the current W/S/A/D sandbox mapping exactly matches build 12340.
|
||||
- Make sprint or free flight available to the production compatibility profile;
|
||||
their profile gate remains a later M02 package.
|
||||
- Implement jump, autorun, left-button select/move or persisted binding settings.
|
||||
- Remove process-wide debug actions; Blizzlike335 sampling ignores them and the
|
||||
movement capability boundary also rejects directly constructed debug requests.
|
||||
|
||||
## Context and boundaries
|
||||
|
||||
@@ -30,8 +31,10 @@ independently testable local movement controller.
|
||||
flowchart LR
|
||||
Devices[Keyboard and mouse] --> InputMap[Godot Input Map]
|
||||
InputMap --> Source[PlayerInputSource]
|
||||
Profile[RenderSandbox or Blizzlike335] --> Source
|
||||
Source --> Intent[MoveIntent]
|
||||
Intent --> Movement[LocalPlayerMovementController]
|
||||
Profile[PlayerMovementCapabilities] --> Movement
|
||||
Movement --> Controller[ThirdPersonWowController adapter]
|
||||
Controller --> Camera[ThirdPersonCameraRig]
|
||||
```
|
||||
@@ -52,11 +55,13 @@ Forbidden dependencies:
|
||||
|
||||
| Symbol | Kind | Purpose | Thread/lifetime | Errors |
|
||||
|---|---|---|---|---|
|
||||
| `MoveIntent` | Immutable value | Carries normalized forward, strafe and vertical axes plus the sandbox sprint request | Created and consumed on the main physics tick; caller retains reference | Constructor clamps axes; no I/O failure |
|
||||
| `MoveIntent` | Immutable value | Carries normalized forward, strafe, vertical and turn axes plus the sandbox sprint request | Created and consumed on the main physics tick; caller retains reference | Constructor clamps axes; no I/O failure |
|
||||
| `MoveIntent.has_translation()` | Query | Reports whether any translation axis is non-zero | Any thread while value remains immutable | None |
|
||||
| `PlayerInputActions` | Constants | Provides stable action names shared by configuration and adapters | Process lifetime | Missing project actions are detected by verification |
|
||||
| `PlayerInputSource.sample_move_intent()` | Adapter method | Samples configured actions for one physics tick | Main thread; returned intent is independent of adapter lifetime | Missing actions resolve to zero strength and are a configuration defect |
|
||||
| `PlayerInputSource.new(profile_id)` | Constructor | Selects sandbox or compatibility action layout once | Scene lifetime | Unknown IDs fail closed to `Blizzlike335` |
|
||||
| `PlayerInputSource.sample_move_intent()` | Adapter method | Samples the selected action layout for one physics tick | Main thread; returned intent is independent of adapter lifetime | Missing actions resolve to zero strength and are a configuration defect |
|
||||
| `PlayerInputSource.compose_move_intent(...)` | Pure factory | Clamps strengths, cancels opposites and normalizes diagonal planar input | Any thread with scalar inputs | None |
|
||||
| `PlayerInputSource.compose_blizzlike_335_move_intent(...)` | Pure factory | Composes Q/E strafe, A/D turn and right-mouse A/D strafe semantics | Any thread with scalar inputs | None |
|
||||
|
||||
## Inputs and outputs
|
||||
|
||||
@@ -65,6 +70,8 @@ Forbidden dependencies:
|
||||
| Input | Movement action strengths | Godot `InputMap`/`Input` | `PlayerInputSource` | Engine-owned snapshot | Sampled on main physics tick |
|
||||
| Input | Mouse action events | Godot `_unhandled_input` dispatch | `ThirdPersonCameraRig` through player dispatch | Engine-owned event | Current input dispatch only |
|
||||
| Output | `MoveIntent` | `PlayerInputSource` | `LocalPlayerMovementController` through scene composition | Immutable caller-held value | One physics tick |
|
||||
| Output | Debug sprint request/vertical axes | `PlayerInputSource` | Capability-gated movement controller | Immutable intent fields | One physics tick |
|
||||
| Output | Signed turn axis | `PlayerInputSource` | `LocalPlayerMovementController` | Immutable scalar | One physics tick |
|
||||
| Output | Camera action names | `PlayerInputActions` | `ThirdPersonCameraRig` | Static constants | Process lifetime |
|
||||
|
||||
Side effects:
|
||||
@@ -81,9 +88,11 @@ flowchart LR
|
||||
Project[project.godot action defaults] --> Map[InputMap]
|
||||
Remap[User or editor remapping] --> Map
|
||||
Map -->|movement strengths| Source[PlayerInputSource]
|
||||
Profile[Selected input profile] --> Source
|
||||
Map -->|camera events| Camera[ThirdPersonCameraRig]
|
||||
Source -->|clamp cancel normalize| Intent[MoveIntent]
|
||||
Intent --> Consumer[LocalPlayerMovementController]
|
||||
Profile[PlayerMovementCapabilities] --> Consumer
|
||||
Consumer --> Adapter[ThirdPersonWowController]
|
||||
```
|
||||
|
||||
@@ -92,7 +101,9 @@ flowchart LR
|
||||
The adapter is stateless. The scene composition root creates one
|
||||
`PlayerInputSource` and `LocalPlayerMovementController` in `_ready`; each physics
|
||||
tick produces a new immutable intent. Flight enabled/disabled state is owned by
|
||||
the movement controller and is not hidden in the input adapter.
|
||||
the movement controller and is not hidden in the input adapter. RenderSandbox
|
||||
retains debug requests in its intent; Blizzlike335 does not sample them, and the
|
||||
immutable movement capability also rejects directly constructed requests.
|
||||
|
||||
## Main sequence
|
||||
|
||||
@@ -106,7 +117,7 @@ sequenceDiagram
|
||||
Engine->>Source: movement action strengths
|
||||
Source->>Intent: compose normalized axes and requests
|
||||
Source-->>Player: sample_move_intent()
|
||||
Player->>Move: advance(intent, selected basis, delta)
|
||||
Player->>Move: calculate yaw delta, then advance(intent, selected basis, delta)
|
||||
Move-->>Player: displacement and velocity state
|
||||
```
|
||||
|
||||
@@ -127,6 +138,7 @@ sequenceDiagram
|
||||
| Conflicting opposite actions | Pure composition | Strengths cancel deterministically | Covered by contract test | Release/remap one action |
|
||||
| Strength outside range | Pure composition | Value clamps to `[0, 1]` before axis calculation | Covered by contract test | Input adapter may be corrected independently |
|
||||
| Controller disabled/unloaded | Scene lifecycle | Sampling stops with physics processing | Existing scene lifecycle | Re-enable or recreate scene |
|
||||
| Debug request in `Blizzlike335` | Input profile and movement capability checks | Input adapter omits it; directly constructed request has no effect | Profile/capability regressions | Use `RenderSandbox` only when debug movement is intended |
|
||||
|
||||
There is no asynchronous operation to cancel and no persisted state to roll back.
|
||||
|
||||