Files
Commonwealth-Online-Public/docs/f4-animation-descriptor.md
T
andrew a6b2505242 Add animation sync docs and descriptor infra
Add detailed design and implementation scaffolding for TiltedEvolution-style animation synchronization. New documentation: animation-architecture-alignment.md, animation-sync-analysis.md, f4-animation-descriptor.md, phase1-3-completion-report.md and updates to dev-log.md describing Phase 1-3 progress. Plugin: introduce F4AnimationDescriptor (plugin/include/F4AnimationDescriptor.h, plugin/src/F4AnimationDescriptor.cpp) and extend remote state handling (plugin/include/F4TRemotePlayerState.h). Integrate protocol/state extensions and refactor points: plugin/src/F4TNetworking.cpp now parses optional actorStateFlags and actionEvents; proxy controller and animation sync files (F4TProxyActorController.cpp, F4TProxyAnimationSync.cpp) updated to support descriptor-based bulk variable snapshots and actor state replication. Server/tools: update server/dev_server_app.py and server/fake_client.py to handle and display the new optional fields. These changes are additive and backward-compatible and set up phases for action capture, dynamic proxy spawn, and action-replay integration.
2026-06-03 16:52:47 +12:00

222 lines
7.7 KiB
Markdown

# Fallout 4 Animation Graph Variables & Descriptor Mapping
## Overview
This document maps Fallout 4's animation graph variable names and indices for the humanoid master behavior graph. This is the foundation for implementing descriptor-based animation synchronization similar to TiltedEvolution's model.
**Goal:** Replace per-frame string-based graph variable writes (e.g., `SetGraphVariableFloat("Speed", 85.0)`) with efficient indexed bulk writes from a pre-computed descriptor table.
---
## Animation Graph Variable Categories
Fallout 4's humanoid master behavior graph organizes variables into three types:
### 1. Float Variables (Locomotion & Direction)
Used to control movement speed, direction, and animation blending.
| Variable Name | Index | Type | Role | Network Sync | Notes |
|---|---|---|---|---|---|
| `Speed` | TBD | Float | Locomotion blend speed (0-105) | ✅ YES | Primary locomotion driver |
| `direction` | TBD | Float | Facing/movement direction (degrees) | ✅ YES | Rotation relative to movement |
| `speedSampled` | TBD | Float | Sampled speed for smoothing | ❌ Derive | Computed from velocity |
| `speedDamped` | TBD | Float | Damped/smoothed speed | ❌ Derive | Animation system internal |
| `pitchGunAim` | TBD | Float | Pitch angle when aiming | ❌ No | Combat specific |
| `weaponAdjust` | TBD | Float | Weapon positioning | ❌ No | Combat specific |
| `velocityZ` | TBD | Float | Vertical velocity | ❌ No | Handled by Havok |
**Speed Buckets (Estimated):**
- Idle: 0.0
- Walk: 35-55
- Run: 55-85
- Sprint: 85-105
### 2. Boolean Variables (State Flags)
Control state transitions and mode changes.
| Variable Name | Index | Type | Role | Network Sync | Notes |
|---|---|---|---|---|---|
| `isSprinting` | TBD | Bool | Sprint mode active | ✅ YES | Triggers sprint animations |
| `isSneaking` | TBD | Bool | Sneak/crouch mode | ✅ YES | Triggers sneak locomotion |
| `isMoving` | TBD | Bool | Any movement active | ✅ YES | Idle ↔ movement transition |
| `bMotionDriven` | TBD | Bool | Motion-driven locomotion | ❌ No | Engine internal |
| `bInMoveState` | TBD | Bool | In locomotion state machine | ❌ No | Engine internal |
| `bSprintOK` | TBD | Bool | Sprint available | ❌ No | Game state dependent |
### 3. Integer Variables (Equipment & State)
Track equipped items and combat state.
| Variable Name | Index | Type | Role | Network Sync | Notes |
|---|---|---|---|---|---|
| `iLeftHandType` | TBD | Int | Left hand weapon/item type | ❌ No | Inventory sync separate |
| `iRightHandEquipped` | TBD | Int | Right hand equipped? (0/1) | ❌ No | Inventory sync separate |
| `iIsInSneak` | TBD | Int | Sneak state (0/1/2) | ❌ No | Derived from isSneaking bool |
---
## Variable Index Discovery Process
To determine actual indices for FO4, we need to:
### 1. Extract Indices via AnimationGraphManager
```cpp
// Pseudocode to dump actual variable indices
void DumpAnimationGraphVariables(RE::Actor* actor) {
auto graphHolder = static_cast<RE::IAnimationGraphManagerHolder*>(actor);
RE::BSTSmartPointer<RE::BSAnimationGraphManager> manager;
if (graphHolder->GetAnimationGraphManagerImpl(manager) && manager) {
// Access manager->behaviorGraph->animationVariables
// Iterate through variable cache and log names + indices
// Compare with known string names to build reverse mapping
}
}
```
### 2. Verify via Creation Kit
- Open the humanoid master behavior graph in Behavior Editor
- Right-click variables to see internal indices/cache layout
- Cross-reference with runtime dumps
### 3. Cross-Reference with CommonLibF4 Headers
- Search `RE/H/BSAnimationGraphManager.h` for hint structs
- Look for variable container definitions
---
## Comparison with TiltedEvolution (Skyrim SE)
TiltedEvolution's `AnimationGraphDescriptor_Master_Behavior.cpp` syncs:
**Skyrim SE Synced Booleans:**
- `kIsSprinting` (index 50)
- `kIsSneaking` (index 186)
- `kbInMoveState` (index 98)
- `kbMotionDriven` (index 41)
- `kisMoving` (index 284)
**Skyrim SE Synced Floats:**
- `kSpeed` (index 0)
- `kSpeedSampled` (index 40)
- `kSpeedDamped` (index 183)
- `kDirection` (index 1)
- `kSpeedWalk`, `kSpeedRun` (indices 4, 5)
**FO4 Likely Similar:**
- Speed float: core locomotion
- Direction float: facing
- isSprinting, isSneaking: bool state flags
- velocityZ: vertical velocity (Havok-driven, derived)
---
## Minimum Viable Sync Set
For initial Phase 1-2 implementation, sync only the essential variables needed for basic locomotion:
| Variable | Type | Index | Reason |
|----------|------|-------|--------|
| `Speed` | Float | TBD | Must have; drives walk/run/sprint |
| `direction` | Float | TBD | Must have; face remote player's heading |
| `isSprinting` | Bool | TBD | Should have; sprint visual distinction |
| `isSneaking` | Bool | TBD | Should have; sneak locomotion + crouch |
| `isMoving` | Bool | TBD | Should have; idle ↔ movement transition |
**Deferred (Phase 2+):**
- Combat variables (aiming, weapon adjust, etc.)
- Jumping/falling (vertical velocity)
- Facial expressions / emotion
- IK targets
---
## Current F4T Implementation (Before Refactor)
Current `F4TProxyAnimationSync.cpp` writes these by string name:
```cpp
// Per-frame, on every proxy actor:
TrySetGraphFloat(graphHolder, "Speed", desired.graphSpeed);
TrySetGraphFloat(graphHolder, "speed", desired.graphSpeed); // fallback
TrySetGraphFloat(graphHolder, "SpeedLower", desired.graphSpeed);
TrySetGraphBool(graphHolder, "IsSprinting", desired.isSprinting);
```
**Issues:**
- String lookup overhead (one `BSFixedString` allocation per write, per frame, per proxy)
- No caching of variable indices
- If a variable name is wrong, silent failure (write returns false)
- No explicit velocity injection (character controller velocity = 0)
---
## Proposed F4AnimationDescriptor Model
After Phase 1 research, we'll build:
```cpp
// plugin/include/F4AnimationDescriptor.h
class F4AnimationDescriptor {
public:
// Per-graph-type lookup
static F4AnimationDescriptor& GetHumanoidDescriptor();
// Bulk read/write by index
void SaveVariablesFromCache(
RE::IAnimationGraphManagerHolder& holder,
AnimationVariableSnapshot& snapshot);
void LoadVariablesToCache(
RE::IAnimationGraphManagerHolder& holder,
const AnimationVariableSnapshot& snapshot);
private:
std::vector<std::string> floatVariableNames;
std::vector<std::string> boolVariableNames;
std::vector<std::string> intVariableNames;
};
```
**Benefits:**
- Pre-computed once at startup
- O(1) index lookups instead of O(n) string searches
- Batch reads/writes in one graph manager lock
- Matches TiltedEvolution's proven architecture
---
## Testing Checklist (Phase 1.3)
- [ ] Verify `Actor::Move(0.016f, {0,0,0}, false)` works on dynamically spawned actors
- [ ] Verify `SetLinearVelocityImpl()` accessible via Move return value
- [ ] Test with proxy in same cell as player
- [ ] Confirm velocity persists across frames
- [ ] Log animation graph state transitions (idle → walk → run)
- [ ] Verify no crashes with velocity injection
- [ ] Document any FO4-specific gotchas vs Skyrim
---
## Next Steps
1. **Phase 1.1:** Use debug logging to extract actual variable indices from running F4
2. **Phase 1.2:** Map TiltedEvolution animation flow into F4T terms (see `animation-architecture-alignment.md`)
3. **Phase 1.3:** Test character controller velocity injection on dynamic proxies
4. **Phase 2:** Extend `RemotePlayerState` with actor state flags + action events
5. **Phase 3:** Implement `F4AnimationDescriptor` class with bulk read/write
---
## References
- TiltedEvolution: `Code/encoding/Structs/Skyrim/AnimationGraphDescriptor_Master_Behavior.cpp`
- CommonLibF4: `RE/H/BSAnimationGraphManager.h`, `RE/H/IAnimationGraphManagerHolder.h`
- Fallout 4 CK: Behavior Editor (humanoid master behavior graph)