Files
Commonwealth-Online-Public/docs/phase6-testing-guide.md
T
andrew 56d9c2c514 Add Phase 6 testing docs and update dev-log
Add comprehensive Phase 6 documentation and testing artifacts: a high-level PHASES-1-6 summary, a Phase 6 quick-start checklist, and a detailed Phase 6 testing & iteration guide. Also append a Phase 6 entry to docs/dev-log.md describing the testing framework, test cases (including the critical velocity→animation test), success criteria, and next steps for in-game validation. These docs prepare the repo for Phase 6 in-game testing and outline debugging, performance benchmarks, and iteration procedures.
2026-06-03 17:09:30 +12:00

12 KiB

Phase 6: Testing & Iteration - Animation Testing Guide

Overview

Phase 6 validates that the TiltedEvolution-aligned animation synchronization works end-to-end in Fallout 4. This document provides testing procedures, expected results, and debugging guidance.

Prerequisites:

  • F4T plugin built and installed
  • Fallout 4 running with F4SE
  • Network relay server running (python server.py)
  • Fake client or second F4T instance ready

Testing Phase 6.1: In-Game Animation Testing

Setup

  1. Start the relay server:

    cd server/
    python server.py
    
  2. Launch F4T with logging enabled:

    • Start Fallout 4 with F4SE
    • Plugin loads (check console for logs)
    • Remote player should spawn near you
  3. If testing with second instance:

    # Terminal 1: Relay server
    python server/server.py
    
    # Terminal 2: Fake client
    python server/fake_client.py
    
    # In-game: Two separate F4T instances, each with F4SE plugin loaded
    

Test 1: Dynamic Proxy Spawning

What to test:

  • Remote player proxy spawns successfully
  • Proxy appears near your position (not at world origin)
  • Multiple proxies can spawn (up to 4 concurrent)

Expected results:

  • Proxy NPC visible in-game
  • Name/ID visible in console logs
  • No crashes on spawn

Debug logs to check:

[Local Player ID: 0] SpawnDynamicProxyActor: Spawned proxy actor <FORMID> for remote player <ID> with base <BASE_FORMID>.
[Local Player ID: 0] Assigned dynamically spawned proxy <FORMID> to remote player <ID>

Test 2: Smooth Movement Synchronization

What to test:

  • Remote proxy moves smoothly to player position
  • Movement is not jerky/teleporting
  • Heading (rotation) updates correctly

Expected results:

  • Proxy walks/runs toward network position
  • Smooth interpolation (lerp alpha 0.15)
  • No position snapping

Debug logs to check:

[Local Player ID: 0] First smoothed runtime proxy movement for remote player <ID>: actor=<FORMID>, alpha=0.15.
[Local Player ID: 0] Moved runtime proxy actor <FORMID> from remote player <ID> state for the first time

Test 3: Velocity Injection & Animation Triggering

CRITICAL TEST: Does velocity injection cause animations to play?

What to test:

  • Proxy plays idle animation when stationary
  • Proxy plays walk animation when moving slowly
  • Proxy plays run animation when moving fast
  • Proxy plays sprint animation when sprinting

Expected results:

Movement State        |  Expected Animation
---------------------|---------------------
Stationary           |  Idle
Speed 0-50 units/s   |  Walk
Speed 50-100 units/s |  Run  
Speed 100+ units/s   |  Sprint

Debug logs to check:

[Local Player ID: 0] ApplyRuntimeProxyTransform: Proxy <FORMID> has AIProcess: true
[Local Player ID: 0] Runtime proxy animation sync <changed/initial> for remote player <ID>: 
    moving=<bool>, sprinting=<bool>, graphSpeed=<float>

If animations DON'T play:

  1. Check velocity is being set (see console logs)
  2. Verify character controller is accessible
  3. Check animation graph manager is available
  4. Look for "Failed to load animation variables" warnings

Test 4: Actor State Flags & Sneak Animation

What to test:

  • Remote player sneaking → proxy crouches
  • Remote player normal → proxy stands
  • State transitions are smooth

Expected results:

  • Proxy visibly crouches when remote player crouches
  • Proxy crouch pose visible (animation, not just flag)
  • No lag in state transition

Debug logs to check:

[Local Player ID: 0] Moved runtime proxy actor <FORMID> ... flags1=<FLAGS1>, flags2=<FLAGS2>

If sneak animation doesn't work:

  • Sneak might require more than just flags
  • May need dedicated action event (Phase 2.3 capture)
  • Document in iteration log

Test 5: Multiple Proxy Actors

What to test:

  • 2 simultaneous proxies move smoothly
  • 3 simultaneous proxies move smoothly
  • 4 simultaneous proxies (max) move smoothly
  • No crashes with multiple proxies

Expected results:

  • Each proxy moves independently to its network position
  • All proxies animate correctly
  • Performance acceptable (no frame rate drops)

Debug logs to check:

[Local Player ID: 0] Runtime proxy slot created for remote player <ID> with holding index <INDEX>.

Testing Phase 6.2: Performance & Stability Profiling

Benchmark: Per-Proxy Update Cost

Metric: Time to update one proxy per frame

Measure:

  1. Enable logging: UpdateProxyAnimationStateDebug calls
  2. Run single proxy moving
  3. Monitor console for timing data
  4. Expected: < 1ms per proxy update

Command (in console):

help F4T  # Check if debug timers are available

Benchmark: Descriptor vs String-Based Writes

Phase 5.3 improvement verification:

Old way (string-based):

  • Multiple TrySetGraphFloat() calls
  • Each call: string allocation + graph lookup

New way (descriptor-based):

  • Single LoadAnimationVariablesToCache() call
  • Array indexing + one graph manager lock

Expected result: Descriptor approach should be ~3-5x faster for animation variable writes.

Stability: Crash Testing

What to test:

  • No crash with 1 proxy moving
  • No crash with 4 proxies moving
  • No crash on proxy disconnect/reconnect
  • No crash on actor reload

Procedure:

  1. Start with 1 proxy moving smoothly
  2. Add proxies one by one
  3. Monitor for crashes
  4. Try disconnecting/reconnecting
  5. Run for 5-10 minutes per configuration

If crashes occur:

  • Note exact conditions
  • Check console for error logs
  • Review actor handle validity
  • Check for memory leaks

Stability: Lag Simulation

What to test:

  • Proxy handles high-frequency position updates (no lag)
  • Proxy handles low-frequency updates (lerp smoothing works)
  • Proxy handles packet loss gracefully

Procedure:

  1. Normal case: Remote sends ~10 Hz (working)
  2. High frequency: Send 30 Hz updates
  3. Low frequency: Send 2 Hz updates
  4. Simulate packet loss: Drop 50% of packets
  5. Verify proxy still animates correctly

Testing Phase 6.3: Iterate & Tune

Variable Index Verification

Goal: Confirm animation graph variable indices are correct for FO4

Current assumptions (from Phase 3):

snapshot.floats[0] = Speed;
snapshot.bools[0] = isSprinting;
snapshot.bools[1] = isSneaking;

How to verify:

  1. If animations work → Indices likely correct
  2. If animations don't play:
    • Enable F4TLocalAnimationGraphDebug.cpp debug logging
    • Dump actual variable indices from local player
    • Compare with descriptor table
    • Update docs/f4-animation-descriptor.md

Debug logging (add if needed):

// In ApplyProxyAnimationFromRemoteStateDescriptorBased
LogInfo(std::format("Variable index 'Speed': {}, value: {}", 
    descriptor.GetFloatVariableIndex("Speed"), desired.graphSpeed));

Velocity Scaling Tuning

Current scaling (from Phase 4):

float speed = distanceDrift / 0.016F;  // Convert to units/sec
float clampedSpeed = min(speed, 400.0F);  // Cap at 400 units/sec

Adjustment procedure:

  1. Watch proxy animations while moving
  2. If walk animation plays but shouldn't → velocity too high
  3. If sprint animation doesn't trigger → velocity too low
  4. Adjust multipliers:
    // Try different scaling
    float speed = (distanceDrift / 0.016F) * 0.8F;  // Reduce by 20%
    

Testing different speeds:

Network Speed | Graph Speed | Expected Animation | Adjust If...
2 units/frame | 125 units/s | Sprint            | Too low → reduce divisor
1 unit/frame  | 62 units/s  | Run               | Too high → increase divisor
0.5 units     | 31 units/s  | Walk              | Not triggering → reduce

Animation Variable Tuning

If animations partially work:

  1. Speed blending isn't smooth:

    • Check speedDamped variable (if implemented)
    • May need to scale Speed over time (lerp, not snap)
  2. Weapon drawn/sneak animation missing:

    • Confirm variable indices in descriptor
    • May need dedicated action events (Phase 2.3)
    • Document as limitation
  3. Transitions are jerky:

    • Velocity might be changing too rapidly
    • Add smoothing: lerp velocity over 0.1-0.2 seconds
    • Or increase lerp alpha on position (currently 0.15)

Test Results Template

Create a new dev-log entry (example):

## Test Session: <DATE> - <TESTER>

### Session Setup
- Number of proxies: 1/2/4
- Duration: 5 minutes
- Network condition: Normal/Lag/Packet Loss

### Test 1: Dynamic Spawning
- [x] Proxy spawned successfully
- [ ] Proxy appeared at correct location
- Result: PASS/FAIL/PARTIAL

### Test 2: Smooth Movement
- [x] Movement is smooth
- [ ] No visible jitter
- Result: PASS/FAIL/PARTIAL

### Test 3: Animation Triggering (CRITICAL)
- [ ] Idle animation plays
- [ ] Walk animation plays
- [ ] Run animation plays
- [ ] Sprint animation plays
- Result: PASS/FAIL/PARTIAL
- Notes: <describe any issues>

### Test 4: Sneak Animation
- [ ] Crouch plays when sneaking
- Result: PASS/FAIL/PARTIAL

### Test 5: Multiple Proxies (4x)
- [ ] All 4 proxies move smoothly
- [ ] No crashes
- [ ] Frame rate acceptable
- Result: PASS/FAIL/PARTIAL

### Performance Metrics
- Per-proxy update time: <N> ms
- Descriptor bulk write time: <N> ms
- Frame rate: <N> fps

### Issues Found
1. <Issue description>
   - Severity: Critical/Major/Minor
   - Workaround: <if any>
   - Fix needed in: <file/phase>

### Conclusion
Overall result: READY FOR PHASE 7 / NEEDS ITERATION / NEEDS FIXES

### Next Steps
- <Action items>

Debugging Checklist

If animations aren't working:

  1. Verify velocity is being set:

    Search logs for: "ApplyRuntimeProxyTransform"
    Should show: Character controller velocity being set
    
  2. Verify actor state flags are applied:

    Search logs for: "Moved runtime proxy actor ... flags1="
    Should show non-zero flags if remote player in combat/sneak
    
  3. Verify animation variables are being written:

    Search logs for: "Runtime proxy animation sync"
    Should show Speed values changing (not always 0)
    
  4. Check if animation graph manager is available:

    Search logs for: "animation graph manager unavailable"
    If present: Graph manager not accessible
    
  5. Enable full animation debugging:

    • Set logging interval to 100ms (from 2s)
    • Enables detailed animation state transitions
    • Generates large log files

Common Issues & Fixes

Issue Possible Cause Fix
Proxy doesn't spawn PlaceAtMe failed Check proxy base actor exists
Proxy stands still Velocity not set Verify character controller access
Walk/run doesn't play Speed variable wrong index Check f4-animation-descriptor.md indices
Sneak doesn't work Needs action replay Phase 2.3 action capture needed
Multiple proxies crash Handle leak Check proxy pool cleanup
Frame rate drops Too many descriptor writes Already optimized; check log frequency

Success Criteria (Phase 6 Complete)

  • Proxy spawns and moves smoothly (dynamic)
  • Velocity injection triggers animation system
  • At least idle/walk/run animations visible
  • Multiple proxies (4x) stable and animating
  • No crashes in 10-minute test session
  • Performance acceptable (< 1ms per proxy update)
  • Actor state flags affect proxy (sneak at minimum)

Ready for Phase 7?

If all tests PASS: → Phase 7: Cleanup & Documentation

If tests FAIL/PARTIAL: → Iterate Phase 6.3 (tune velocity/variables) → Return to Phase 5 if infrastructure issues found

If tests CRASH: → Debug and fix issues → Return to Phase 4-5 as needed