# 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:** ```bash 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:** ```bash # 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 for remote player with base . [Local Player ID: 0] Assigned dynamically spawned proxy to remote player ``` ### 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 : actor=, alpha=0.15. [Local Player ID: 0] Moved runtime proxy actor from remote player 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 has AIProcess: true [Local Player ID: 0] Runtime proxy animation sync for remote player : moving=, sprinting=, graphSpeed= ``` **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 ... flags1=, 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 with holding 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):** ```cpp 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):** ```cpp // In ApplyProxyAnimationFromRemoteStateDescriptorBased LogInfo(std::format("Variable index 'Speed': {}, value: {}", descriptor.GetFloatVariableIndex("Speed"), desired.graphSpeed)); ``` ### Velocity Scaling Tuning **Current scaling (from Phase 4):** ```cpp 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: ```cpp // 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: - ### 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: ### 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: ms - Descriptor bulk write time: ms - Frame rate: fps ### Issues Found 1. - Severity: Critical/Major/Minor - Workaround: - Fix needed in: ### Conclusion Overall result: READY FOR PHASE 7 / NEEDS ITERATION / NEEDS FIXES ### Next Steps - ``` --- ## 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