Repo Cleanup

This commit is contained in:
2026-07-10 17:30:10 +12:00
parent ca92123cd9
commit 5b031975d0
58 changed files with 112 additions and 2464 deletions
+5 -5
View File
@@ -1,8 +1,8 @@
# Contributing # Contributing
Commonwealth Online is currently in the research and prototype stage. Commonwealth Online is an active Fallout 4 multiplayer mod in iterative development.
At this stage, contributions should focus on documentation, research, setup notes, tooling experiments, and small isolated prototypes. Contributions should stay focused, documented, and safe to test in a clean Fallout 4 profile.
## Current Contribution Areas ## Current Contribution Areas
@@ -19,11 +19,11 @@ Useful contributions include:
## Scope ## Scope
Please keep contributions focused on the first prototype goal: Please keep contributions aligned with the current project scope:
> Two Fallout 4 clients in a controlled test environment, with each player visible as a synced remote actor. > Dedicated-server Fallout 4 multiplayer with transform sync, proxy actors, and expanding presence/infrastructure features.
Avoid adding large systems before the core prototype works. Avoid large unrelated rewrites or gameplay systems that are not part of the current milestone.
Out of scope for early development: Out of scope for early development:
+5 -4
View File
@@ -136,12 +136,11 @@ plugin/ F4SE/CommonLibF4 C++ plugin
server/ Python relay, dev GUI, fake clients server/ Python relay, dev GUI, fake clients
creation-kit/ ESP sources, Papyrus scripts, assets creation-kit/ ESP sources, Papyrus scripts, assets
ui/ PrismaUI HTML/JS (server browser) ui/ PrismaUI HTML/JS (server browser)
protocol/ Detailed packet and sync documentation docs/ Architecture, setup, protocol, dev notes, roadmap
docs/ Architecture, setup, protocol overview, dev notes docs/protocol/ Detailed packet and sync field reference
ThirdParty/ Vendored submodules (CommonLibF4/PrismaUI, Ultralight, etc.) ThirdParty/ Vendored submodules (CommonLibF4/PrismaUI, Ultralight, etc.)
Branding/ Project logos Branding/ Project logos
tools/ Helper utilities tools/ Helper utilities and build scripts
scripts/ Build/deploy helpers
test-data/ Example packets test-data/ Example packets
screenshots/ Development screenshots screenshots/ Development screenshots
build/ Staged mod output (generated by build-all.bat) build/ Staged mod output (generated by build-all.bat)
@@ -158,9 +157,11 @@ Root batch scripts: `build-all.bat`, `deploy-all.bat`, `build.bat`, `compile-pap
| [`docs/setup.md`](docs/setup.md) | Build, deploy, submodules, main-menu notes | | [`docs/setup.md`](docs/setup.md) | Build, deploy, submodules, main-menu notes |
| [`docs/architecture.md`](docs/architecture.md) | Plugin, server, proxy, threading model | | [`docs/architecture.md`](docs/architecture.md) | Plugin, server, proxy, threading model |
| [`docs/protocol.md`](docs/protocol.md) | Message types and LAN discovery | | [`docs/protocol.md`](docs/protocol.md) | Message types and LAN discovery |
| [`docs/protocol/`](docs/protocol/) | Detailed packet field reference |
| [`docs/limitations.md`](docs/limitations.md) | Technical limits and unsupported systems | | [`docs/limitations.md`](docs/limitations.md) | Technical limits and unsupported systems |
| [`docs/version-targets.md`](docs/version-targets.md) | Supported game/F4SE versions | | [`docs/version-targets.md`](docs/version-targets.md) | Supported game/F4SE versions |
| [`docs/project-comparison.md`](docs/project-comparison.md) | Commonwealth Online vs DoxyCoSync | | [`docs/project-comparison.md`](docs/project-comparison.md) | Commonwealth Online vs DoxyCoSync |
| [`docs/ROADMAP.md`](docs/ROADMAP.md) | Vertical-slice roadmap and milestones |
| [`changelog.md`](changelog.md) | Record of code and documentation changes | | [`changelog.md`](changelog.md) | Record of code and documentation changes |
| [`docs/dev-log.md`](docs/dev-log.md) | Milestones, testing notes, next steps | | [`docs/dev-log.md`](docs/dev-log.md) | Milestones, testing notes, next steps |
+1 -1
View File
@@ -27,7 +27,7 @@ if not exist "%UL_SDK%\include" (
echo Linking Ultralight SDK from: echo Linking Ultralight SDK from:
echo %UL_SDK% echo %UL_SDK%
powershell -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%scripts\setup-ultralight-link.ps1" -SdkPath "%UL_SDK%" powershell -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%tools\scripts\setup-ultralight-link.ps1" -SdkPath "%UL_SDK%"
if errorlevel 1 ( if errorlevel 1 (
echo Failed to link Ultralight SDK. echo Failed to link Ultralight SDK.
exit /b 1 exit /b 1
+1
View File
@@ -21,6 +21,7 @@ For testing notes, milestone summaries, known issues, and next steps, see [`docs
- Updated `server/requirements.txt` with `typer` and `rich` dependencies. - Updated `server/requirements.txt` with `typer` and `rich` dependencies.
### Changed ### Changed
- Repository cleanup: moved `protocol/` and `ROADMAP.md` under `docs/`, moved decompiled `Interface/` reference assets to `docs/reference/Interface/`, moved `setup-ultralight-link.ps1` to `tools/scripts/`, removed stale phase/milestone docs and unused `steam_interfaces.txt`, and added `docs/README.md` as a documentation index.
- Documentation updated: `docs/setup.md` now includes quick-start CLI hosting instructions. - Documentation updated: `docs/setup.md` now includes quick-start CLI hosting instructions.
### Fixed ### Fixed
-319
View File
@@ -1,319 +0,0 @@
# FFDec guide — add Multiplayer button to MainMenu.swf
> **Deprecated:** Use C++ runtime injection instead. See [`MainMenu_Injection.md`](MainMenu_Injection.md). Do not deploy a patched `MainMenu.swf` for Commonwealth Online.
Step-by-step instructions for adding the **Multiplayer** main-menu item using [JPEXS FFDec](https://github.com/jindrapetrik/jpexs-decompiler/releases), without breaking **Settings → Gameplay / Display / Audio**.
This guide is kept for historical reference only.
---
## Before you start
### Restore vanilla SWF
Always patch from the vanilla file, not an old broken copy:
```powershell
.\tools\restore-vanilla-mainmenu.ps1
```
Or manually copy `Interface/MainMenu.swf.vanilla.bak``Interface/MainMenu.swf`.
Vanilla size is **61,959 bytes**. If your file is **64 KB+**, it is probably a bad re-import — restore and start again.
### Requirements
- **FFDec** installed
- Game launched via **F4SE** with `CommonwealthOnline.dll` in `Data/F4SE/Plugins/`
- Loose Interface overrides enabled in `%USERPROFILE%/Documents/My Games/Fallout4/Fallout4Custom.ini`:
```ini
[Archive]
bInvalidateOlderFiles=1
```
### Critical rule
| Do | Don't |
|----|--------|
| Edit **individual methods** (double-click method in traits list) | Paste the full `MainMenu.as` export into the class editor |
| Save after each small edit | Use **Import script** on the whole `MainMenu` class |
| Keep SWF ~6263 KB | Re-export the entire decompiled script |
Full re-import recompiles `RequestOptions` and breaks settings sub-menus. Controls will still work; Gameplay / Display / Audio will crash.
---
## FFDec navigation
1. Open **`Interface/MainMenu.swf`** in FFDec.
2. Left tree: **scripts → MainMenu**.
3. You should see a **traits / members list** (constants, functions).
4. **Double-click a method name** (e.g. `InitList`) to open **only that method** in the editor.
5. After each edit: apply/save the method, then **File → Save** the SWF.
Do **not** use **Edit ActionScript** on the entire `MainMenu` class if FFDec offers a single giant class view — use per-method editing instead.
---
## Summary of changes
| # | Where in FFDec | What |
|---|----------------|------|
| 1 | Class constants | Add `MULTIPLAYER_INDEX` |
| 2 | Method `InitList` | Push Multiplayer row after Load |
| 3 | Method `onMainListItemPress` | Add `case` for Multiplayer |
| 4 | New method `CloseMultiplayerBrowser` | Helper (recommended) |
| 5 | Method `set currentState` | Call close helper when leaving main panel |
| 6 | Method `onMainListItemPress` | Close browser when another item is selected |
Changes **46** are recommended so the HTML browser closes immediately when opening Settings, etc. The plugin also hides the browser when `currentState` leaves `MAIN_STATE`, but the SWF hooks make it feel instant.
---
## Change 1 — Add index constant
**FFDec:** `MainMenu` → constants section (near other `*_INDEX` constants)
**Find this block** (search for `INSTALLED_CONTENT_INDEX`):
```actionscript
private const INSTALLED_CONTENT_INDEX:Number = 14;
private const MAIN_PANEL_BACKGROUND:uint = 0;
```
**Insert between those lines:**
```actionscript
private const MULTIPLAYER_INDEX:Number = 15;
```
Index `15` is unused in vanilla (highest defined index is `14`).
---
## Change 2 — Add menu row in `InitList`
**FFDec:** `MainMenu` → method **`InitList`**
**Find this block** (search for `"$LOAD"` push — it appears after the `$NEW` block on title screen):
```actionscript
this.MainPanel_mc.List_mc.entryList.push({
"text":"$LOAD",
"disabled":!this.HasRecentSave || !param6,
"index":this.LOAD_INDEX
});
if(param8 == true)
```
**Replace with** (add Multiplayer block between Load and `if(param8 == true)`):
```actionscript
this.MainPanel_mc.List_mc.entryList.push({
"text":"$LOAD",
"disabled":!this.HasRecentSave || !param6,
"index":this.LOAD_INDEX
});
if(!this.PauseMode)
{
this.MainPanel_mc.List_mc.entryList.push({
"text":"Multiplayer",
"index":this.MULTIPLAYER_INDEX
});
}
if(param8 == true)
```
**Notes:**
- `"Multiplayer"` is a literal label (no `$` prefix). Strings with `$` are looked up in `Interface/Translate_en.txt`.
- `!this.PauseMode` limits the row to the **title screen**, not the in-game pause menu.
- Row appears between **Load** and **Add-ons** (or PS5 transfer if enabled).
---
## Change 3 — Handle click in `onMainListItemPress`
**FFDec:** `MainMenu` → method **`onMainListItemPress`**
**Find this block** (search for `case this.HELP_INDEX:`):
```actionscript
break;
case this.HELP_INDEX:
this.StartState(this.HELP_STATE);
this.BGSCodeObj.PlayOKSound();
break;
```
**Insert immediately before** `case this.HELP_INDEX:`:
```actionscript
break;
case this.MULTIPLAYER_INDEX:
this.BGSCodeObj.PlayOKSound();
if(root.f4se != null && root.f4se.plugins != null && root.f4se.plugins.commonwealthOnline != null)
{
root.f4se.plugins.commonwealthOnline.openManager();
}
break;
case this.HELP_INDEX:
this.StartState(this.HELP_STATE);
this.BGSCodeObj.PlayOKSound();
break;
```
This calls the C++ API registered by `CommonwealthOnline.dll` (`openManager` → PrismaUI server browser). **F9** still toggles the same browser.
---
## Change 4 — Add `CloseMultiplayerBrowser` method
**FFDec:** `MainMenu`**add new method** (right-click class → Add script / Add method, or paste near other private helpers like `onMainListItemPress`)
**Add this entire method:**
```actionscript
private function CloseMultiplayerBrowser() : *
{
if(root.f4se != null && root.f4se.plugins != null && root.f4se.plugins.commonwealthOnline != null)
{
root.f4se.plugins.commonwealthOnline.closeManager();
}
}
```
---
## Change 5 — Close browser in `set currentState`
**FFDec:** `MainMenu` → method **`set currentState`** (may appear as `currentState` setter)
**Find:**
```actionscript
public function set currentState(param1:String) : *
{
this.strCurrentState = param1;
this.UpdateButtons(param1);
this.UpdateStateFocus(param1);
}
```
**Change to:**
```actionscript
public function set currentState(param1:String) : *
{
this.strCurrentState = param1;
if(param1 != this.MAIN_STATE)
{
this.CloseMultiplayerBrowser();
}
this.UpdateButtons(param1);
this.UpdateStateFocus(param1);
}
```
---
## Change 6 — Close browser when another main-menu item is selected
**FFDec:** `MainMenu` → method **`onMainListItemPress`** (same method as Change 3)
**Find** the start of the `else` branch, after the `while` loop that returns to main state:
```actionscript
while(this.strCurrentState != this.MAIN_STATE)
{
this.onCancelPress(true,false);
}
if(this.MainPanel_mc.List_mc.selectedEntry.index == this.CONTINUE_INDEX && this.PauseMode)
```
**Insert between the `while` loop and the `CONTINUE_INDEX` check:**
```actionscript
while(this.strCurrentState != this.MAIN_STATE)
{
this.onCancelPress(true,false);
}
if(this.MainPanel_mc.List_mc.selectedEntry.index != this.MULTIPLAYER_INDEX)
{
this.CloseMultiplayerBrowser();
}
if(this.MainPanel_mc.List_mc.selectedEntry.index == this.CONTINUE_INDEX && this.PauseMode)
```
---
## Save and deploy
1. **File → Save** in FFDec (overwrite `Interface/MainMenu.swf`).
2. Check file size: should be roughly **62,00063,500 bytes**. If **64,000+**, restore vanilla and redo using **method-only** edits.
3. Copy to game:
```
Fallout 4/Data/Interface/MainMenu.swf
```
4. Launch via **F4SE**.
---
## Test checklist
| Step | Expected |
|------|----------|
| Main menu (title screen) | **Multiplayer** appears after **Load** |
| Pause menu → Settings | **No** Multiplayer row |
| Click **Multiplayer** | Server browser opens |
| **Settings → Gameplay** | No crash |
| **Settings → Display** | No crash |
| **Settings → Audio** | No crash |
| **Settings → Controls** | Still works |
| Open Multiplayer, then **Settings** | Browser closes |
| **F9** | Still toggles browser |
---
## Troubleshooting
### Settings sub-menus crash again
You likely re-imported the full class. Run `.\tools\restore-vanilla-mainmenu.ps1` and redo changes **16** using **per-method** editing only.
### Multiplayer row missing
- Confirm `bInvalidateOlderFiles=1` in `Fallout4Custom.ini`.
- Confirm loose `Data/Interface/MainMenu.swf` exists and is not overridden by another mod (check MO2 load order).
- Confirm you added the `InitList` block with `if(!this.PauseMode)`.
### Multiplayer row visible but click does nothing
- Launch via **F4SE**, not vanilla exe.
- Confirm `CommonwealthOnline.dll` is loading (check `Documents/My Games/Fallout4/F4SE/CommonwealthOnline.log`).
- Confirm Change **3** (`case this.MULTIPLAYER_INDEX`) is present.
### Button shows `$MULTIPLAYER` or wrong text
Use literal `"Multiplayer"` (no `$`), or add a translation key to `Interface/Translate_en.txt`.
---
## Reference files
| File | Purpose |
|------|---------|
| [`MainMenu.swf.vanilla.bak`](../MainMenu.swf.vanilla.bak) | Untouched vanilla backup |
| [`scripts/MainMenu.as`](scripts/MainMenu.as) | Full decompiled reference — **do not import wholesale** |
| [`PATCH_MainMenu_Multiplayer.md`](PATCH_MainMenu_Multiplayer.md) | Short overview |
| [`../../tools/restore-vanilla-mainmenu.ps1`](../../tools/restore-vanilla-mainmenu.ps1) | Restore vanilla SWF from game BA2 |
Plugin API (already implemented in C++):
- `root.f4se.plugins.commonwealthOnline.openManager()`
- `root.f4se.plugins.commonwealthOnline.closeManager()`
+1 -1
View File
@@ -106,7 +106,7 @@ The `index` field is a **logical ID** used by `onMainListItemPress()` — it is
### Vanilla logical indices ### Vanilla logical indices
From `Interface/exported/scripts/MainMenu.as` (reference only — do not re-import): From `docs/reference/Interface/exported/scripts/MainMenu.as` (reference only — do not re-import):
| Constant | Index | Typical label | | Constant | Index | Typical label |
|---|---|---| |---|---|---|
+2 -5
View File
@@ -55,9 +55,6 @@ In `CommonwealthOnline.log`, look for `[MainMenuInject]` lines:
- `Injected Multiplayer row after Load.` - `Injected Multiplayer row after Load.`
- `Registered ITEM_PRESS listener ('…').` - `Registered ITEM_PRESS listener ('…').`
## Deprecated approach ## Reference material
The FFDec SWF patch guide is superseded by this document: Decompiled vanilla `MainMenu` ActionScript for reading only (do not re-import) lives under [`docs/reference/Interface/`](reference/Interface/).
- [`FFDEC_MainMenu_Multiplayer_Guide.md`](FFDEC_MainMenu_Multiplayer_Guide.md) — historical reference only
- [`PATCH_MainMenu_Multiplayer.md`](../Interface/exported/PATCH_MainMenu_Multiplayer.md) — historical reference only
-159
View File
@@ -1,159 +0,0 @@
# MainMenu.swf — Multiplayer button patch guide
> **Full FFDec walkthrough:** see [`FFDEC_MainMenu_Multiplayer_Guide.md`](FFDEC_MainMenu_Multiplayer_Guide.md) for exact search anchors, before/after snippets, and a test checklist.
Add a **Multiplayer** item to the title-screen main menu. Selecting it calls `root.f4se.plugins.commonwealthOnline.openManager()`, which opens the PrismaUI server browser (same as **F9**).
## CRITICAL — edit methods, not the whole script
**Never** paste the full exported `MainMenu.as` into FFDec or use **Import script** on the whole class. That recompiles `RequestOptions` from decompiled source and **breaks Settings → Gameplay / Display / Audio**.
In FFDec, edit **individual methods** (double-click the method under **MainMenu** traits). FFDec then recompiles only that method and leaves vanilla bytecode (including `RequestOptions`) intact.
Restore vanilla any time:
```powershell
.\tools\restore-vanilla-mainmenu.ps1
```
## Prerequisites
- [JPEXS FFDec](https://github.com/jindrapetrik/jpexs-decompiler/releases)
- Game launched via **F4SE** with `CommonwealthOnline.dll` installed
- Loose Interface overrides enabled in `Fallout4Custom.ini`:
```ini
[Archive]
bInvalidateOlderFiles=1
```
## FFDec workflow
1. Copy `Interface/MainMenu.swf.vanilla.bak``Interface/MainMenu.swf` (start from vanilla every time).
2. Open `Interface/MainMenu.swf` in FFDec.
3. In the left tree: **scripts → MainMenu** (class traits list, not “Edit ActionScript” on the whole class).
4. Apply the **four method-level edits** below (double-click each method to open its editor, save after each).
5. **File → Save**.
6. Sanity check: patched SWF should stay **~6263 KB**. If it jumps to **64 KB+**, settings are likely broken — restore vanilla and retry using **method** editors only.
7. Copy to `Fallout 4/Data/Interface/MainMenu.swf`.
8. Test **Settings → Gameplay / Display / Audio** first, then **Multiplayer**.
---
## Edit 1 — Add constant (class body)
Open the **MainMenu** class initializer / constants section (or edit at top of class in trait view). After `INSTALLED_CONTENT_INDEX`:
```actionscript
private const MULTIPLAYER_INDEX:Number = 15;
```
Index `15` is unused in vanilla (highest is `INSTALLED_CONTENT_INDEX = 14`).
---
## Edit 2 — `InitList()` — add menu row
In **`InitList`**, find the `$LOAD` push (after `$NEW` on title screen). Insert **before** the PS5 transfer block:
```actionscript
this.MainPanel_mc.List_mc.entryList.push({
"text":"$LOAD",
"disabled":!this.HasRecentSave || !param6,
"index":this.LOAD_INDEX
});
if(!this.PauseMode)
{
this.MainPanel_mc.List_mc.entryList.push({
"text":"Multiplayer",
"index":this.MULTIPLAYER_INDEX
});
}
if(param8 == true)
```
Use literal `"Multiplayer"` (no `$` prefix) unless you add a row to `Interface/Translate_en.txt`.
---
## Edit 3 — `onMainListItemPress()` — handle click
In the main `switch(this.MainPanel_mc.List_mc.selectedEntry.index)`, add **before** `case this.HELP_INDEX:`:
```actionscript
case this.MULTIPLAYER_INDEX:
this.BGSCodeObj.PlayOKSound();
if(root.f4se != null && root.f4se.plugins != null && root.f4se.plugins.commonwealthOnline != null)
{
root.f4se.plugins.commonwealthOnline.openManager();
}
break;
```
---
## Edit 4 (recommended) — auto-close browser
The plugin also hides the browser when the menu leaves `MAIN_STATE`, but these SWF hooks close it immediately when navigating away.
### 4a — Add new method `CloseMultiplayerBrowser`
In FFDec: **MainMenu → right-click → Add script** / add method:
```actionscript
private function CloseMultiplayerBrowser() : *
{
if(root.f4se != null && root.f4se.plugins != null && root.f4se.plugins.commonwealthOnline != null)
{
root.f4se.plugins.commonwealthOnline.closeManager();
}
}
```
### 4b — Edit `set currentState`
After `this.strCurrentState = param1;`:
```actionscript
this.strCurrentState = param1;
if(param1 != this.MAIN_STATE)
{
this.CloseMultiplayerBrowser();
}
this.UpdateButtons(param1);
```
### 4c — Edit `onMainListItemPress`
After the `while(this.strCurrentState != this.MAIN_STATE)` loop, before the `switch`:
```actionscript
if(this.MainPanel_mc.List_mc.selectedEntry.index != this.MULTIPLAYER_INDEX)
{
this.CloseMultiplayerBrowser();
}
```
---
## Test plan
| Step | Expected |
|------|----------|
| Main menu shows **Multiplayer** between Load and Add-ons | Yes |
| Click **Multiplayer** | Server browser opens |
| Open **Settings → Display** | No crash |
| Open **Settings → Gameplay / Audio** | No crash |
| Select **Continue** while browser open | Browser closes |
| **F9** | Still toggles browser |
---
## Reference
Full decompiled class (do **not** import wholesale): [`scripts/MainMenu.as`](scripts/MainMenu.as)
Plugin API registered in `CommonwealthOnline.dll`:
- `root.f4se.plugins.commonwealthOnline.openManager()`
- `root.f4se.plugins.commonwealthOnline.closeManager()`
-390
View File
@@ -1,390 +0,0 @@
# Phases 1-6 Complete: TiltedEvolution Alignment Implementation Summary
## Project Milestone: Animation Synchronization Architecture Complete ✅
**Date:** June 3, 2026
**Status:** Ready for Phase 6 In-Game Testing
**Effort:** ~40 hours (Phases 1-5 complete)
---
## Overview
Successfully aligned Commonwealth Online with TiltedEvolution's proven multiplayer animation synchronization architecture. Implemented complete stack from network protocol through animation descriptor system to action replay infrastructure.
**Key Achievement:** Proxy actors can now theoretically display working animations by:
1. Dynamically spawning proxies
2. Injecting character controller velocity
3. Replicating actor state flags
4. Synchronizing animation graph variables via descriptor indexing
5. Queuing discrete action events for replay
---
## Phase-by-Phase Deliverables
### Phase 1: Blueprint & Research ✅
**Status:** Complete
**Output:** Architecture documentation + TiltedEvolution alignment analysis
- Created `docs/f4-animation-descriptor.md`
- FO4 humanoid graph variable mapping (9 floats, 6 bools, 3 ints)
- Comparison with Skyrim SE model
- Variable roles and network sync requirements
- Created `docs/animation-architecture-alignment.md`
- Component-by-component alignment (7 major components)
- Data flow diagrams (3 flow models)
- FO4-specific adaptations identified
- Integration points for Phases 2-5 documented
- Created `docs/animation-sync-analysis.md`
- Detailed analysis of current failure modes
- TiltedEvolution solutions explained
- Root cause analysis documented
**Result:** Clear architectural path forward with no blockers identified.
---
### Phase 2: State & Protocol ✅
**Status:** Complete
**Output:** Network protocol extended + state structure updated
**Modified Files:**
- `plugin/include/F4TRemotePlayerState.h`
- Extended struct with actor state flags (flags1, flags2)
- Added action event queue
- Created `RemoteActionEvent` struct
- `plugin/src/F4TNetworking.cpp`
- Updated JSON parsing for new fields
- Maintained backward compatibility (optional fields)
- Enhanced logging with flag values
- `server/fake_client.py`
- Added actor state flag parsing
- Updated display to show flags in hex format
**New Files:**
- `docs/protocol-phase2-extensions.md`
- Full protocol specification
- Actor state flag reference table
- Action event structure documented
**Result:** Network protocol extensible for action replay + state sync. Fully backward compatible.
---
### Phase 3: Animation Descriptors ✅
**Status:** Complete
**Output:** Descriptor-based variable indexing infrastructure
**Created Files:**
- `plugin/include/F4AnimationDescriptor.h`
- Class definition with full API
- Singleton pattern
- Public query/read/write methods
- `plugin/src/F4AnimationDescriptor.cpp`
- Implementation with humanoid graph variable tables
- Reverse lookup maps (name → index)
- Bulk read/write methods (`SaveAnimationVariablesFromCache`, `LoadAnimationVariablesToCache`)
- Thread-safe initialization
**Features:**
- Pre-computed variable tables (one-time init)
- Efficient O(1) index-based access
- Single graph manager lock for batch operations
- Graceful fallback to string-based API
**Result:** Efficient animation variable synchronization with 3-5x performance gain over string-based writes.
---
### Phase 4: Dynamic Proxy Spawning & Velocity ✅
**Status:** Complete
**Output:** Dynamic proxy spawning + velocity injection integration
**Modified Files:**
- `plugin/src/F4TProxyActorController.cpp`
- Added `g_dynamicProxyPool` (playerId → ActorHandle map)
- Implemented `SpawnDynamicProxyActor()` function
- Implemented `GetOrSpawnDynamicProxy()` function
- Modified `TryResolveSlotProxy()` to prefer dynamic spawn
- Enhanced `MoveSlotProxyToRemotePlayer()` with actor state flag application
**New Infrastructure:**
- Dynamic spawning via `Player::PlaceAtMe()`
- Proxy reuse system (keep actors, reuse by playerId)
- Character controller velocity injection (already present, verified)
- Actor state flag synchronization
**Result:** Proxies spawn dynamically with proper velocity injection + state synchronization. Fallback to pre-placed pool maintained.
---
### Phase 5: Action Replay & Descriptor Sync ✅
**Status:** Complete
**Output:** Action queue system + descriptor-based animation sync
**Created Files:**
- `plugin/include/F4RemoteActionComponent.h`
- `RemoteActionSnapshot` struct
- `RemoteActionQueue` class
- Enqueue/replay/clear methods
- `plugin/src/F4RemoteActionComponent.cpp`
- Full action queue implementation
- Actor state application from snapshot
- Animation variable loading via descriptor
- Comprehensive logging
**Modified Files:**
- `plugin/src/F4TProxyActorController.cpp`
- Added `actionQueue` member to `ProxyActorSlot`
- Each proxy has its own action queue
- `plugin/src/F4TProxyAnimationSync.cpp`
- Added `ApplyProxyAnimationFromRemoteStateDescriptorBased()`
- Uses descriptor-based bulk writes
- Replaces per-frame string lookups
**Result:** Action replay infrastructure + efficient descriptor-based animation sync ready for integration.
---
### Phase 6: Testing & Iteration Framework ✅
**Status:** Ready for In-Game Testing
**Output:** Comprehensive testing documentation + quick-start guide
**Created Files:**
- `docs/phase6-testing-guide.md` (8,000+ words)
- Complete testing procedures
- 5 critical test categories
- Performance benchmarking
- Debugging checklist
- Common issues + fixes
- Success criteria
- `docs/phase6-quick-start.md`
- 30-minute critical path for testing
- Console log patterns (good vs bad)
- Performance expectations
- Common fixes quick reference
- Results template
**Test Coverage:**
1. Dynamic Proxy Spawning
2. Smooth Movement Synchronization
3. Velocity Injection & Animation Triggering (CRITICAL)
4. Actor State Flags & Sneak Animation
5. Multiple Proxy Actors (stability)
6. Performance & Stability Profiling
7. Velocity Scaling Tuning
8. Variable Index Verification
**Result:** Ready for in-game validation. Testing framework ensures comprehensive coverage of all phases.
---
## Architecture Summary
### Before (Pre-Phase 1)
```
SetPosition-only movement
No character controller velocity
Animation system sees 0 velocity
No animations play ❌
```
### After (Post-Phase 5)
```
Dynamic proxy spawn
+ Character controller velocity injection
+ Actor state flag synchronization
+ Descriptor-based animation variable sync
+ Action event replay queue
Animation system sees real velocity + proper graph state
Animations should play ✅ (to be verified Phase 6)
```
---
## Code Statistics
| Metric | Count |
|--------|-------|
| Files created | 8 |
| Files modified | 6 |
| C++ code added | ~800 lines |
| Python code updated | ~100 lines |
| Documentation added | ~15,000 words |
| Total lines of code | ~5,000 lines |
---
## Key Technical Achievements
1. **Descriptor-Based Animation Sync (Phase 3+5)**
- O(1) indexed variable access vs O(n) string lookup
- Single graph manager lock vs multiple locks
- 3-5x performance improvement
2. **Dynamic Proxy Spawning (Phase 4)**
- Replaced pre-placed pool with dynamic spawning
- Maintains slot-based reuse (4 concurrent proxies)
- Fallback to pre-placed for compatibility
3. **Character Controller Velocity Injection (Phase 4)**
- Verified working via `Move(0.016f, delta, false)` + `SetLinearVelocityImpl()`
- Enables animation system velocity evaluation
- Clamps to 400 units/sec max
4. **Actor State Synchronization (Phase 4)**
- Replicates `actorState.flags1/2` from remote player
- Applied before animation sync for FSM precedence
- Enables state-driven animation transitions
5. **Action Replay Infrastructure (Phase 5)**
- `RemoteActionQueue` per proxy slot
- Action snapshots with full state
- Max 16 pending actions per queue
- Ready for Phase 2.3 action capture
---
## Testing Readiness
**Ready for Phase 6 In-Game Testing:**
- ✅ Dynamic proxies spawn successfully
- ✅ Velocity injection framework in place
- ✅ Actor state flags integrated
- ✅ Descriptor-based sync implemented
- ✅ Action queue infrastructure ready
- ✅ Network protocol extended
- ✅ Comprehensive testing documentation
- ✅ Quick-start guide for testing
**Critical Test (Test 3):**
- Will verify if velocity injection triggers animations
- If PASS → Proceed to Phase 7
- If FAIL → Iterate Phase 6.3 (tune variables/scaling)
---
## What's Next
### Phase 6: In-Game Testing (NOW)
1. Build plugin with all changes
2. Load Fallout 4 with F4SE
3. Run Test 1-5 as per guide
4. Document results
5. Tune if needed (Phase 6.3)
### Phase 7: Cleanup & Documentation (After Phase 6)
1. Remove debug gates/scaffolding
2. Finalize architecture documentation
3. Update protocol documentation
4. Create animation descriptor guide
5. Production-ready code
---
## Known Unknowns (To Be Verified Phase 6)
1. **Will velocity injection trigger animations on dynamic proxies?**
- Theoretical: Yes (all pieces in place)
- Practical: To be verified in-game
2. **Are animation variable indices correct for FO4?**
- Based on: Skyrim SE comparison + FO4 theory
- Verification: Phase 6 testing + debug logging
3. **Is 400 units/sec velocity clamping appropriate?**
- Assumption: Yes, based on estimated graph limits
- Tuning: Phase 6.3 iteration if needed
4. **Will actor state flags properly guide animation FSM?**
- Theory: Yes (same as Skyrim)
- Practice: Phase 6 testing
5. **Will action replay (Phase 2.3) integrate cleanly?**
- Infrastructure: Ready (Phase 5.1)
- Capture: Deferred to Phase 7 or later
---
## Success Metrics
### Phase 1-5 (Completed)
- ✅ Architecture aligned with TiltedEvolution
- ✅ Protocol extended without breaking changes
- ✅ Descriptor infrastructure implemented
- ✅ Dynamic spawning system operational
- ✅ Action queue infrastructure ready
- ✅ Code compiles without errors
- ✅ ~5,000 lines of tested code
### Phase 6 (In Progress)
- Testing framework: ✅ Complete
- In-game validation: ⏳ Awaiting developer testing
- Performance profiling: ⏳ Awaiting testing
- Variable tuning: ⏳ Awaiting testing
### Phase 7 (Pending)
- Code cleanup
- Documentation finalization
- Production release
---
## Repository Status
**All files committed:**
```
Phases 1-5 code: Complete
Phases 1-5 docs: Complete
Phase 6 testing framework: Complete
Ready for in-game validation
```
**Total effort:** ~40 hours (Phases 1-5)
**Estimated Phase 6:** 2-4 hours testing + tuning
**Estimated Phase 7:** 2-3 hours cleanup + docs
**Total project:** ~48-50 hours
---
## Critical Success Path for Phase 6
1. Build + load plugin
2. Run Test 3 (Animations)
- IF PASS: Proceed to Phase 7
- IF FAIL: Debug + iterate Phase 6.3
3. Document results
4. Proceed to Phase 7 when all tests pass
**Recommendation:** Run Test 3 first as it's the make-or-break test for the entire animation system.
---
## Conclusion
Phases 1-5 successfully implement a complete, TiltedEvolution-aligned animation synchronization architecture for Commonwealth Online. All foundational systems are in place:
- ✅ Descriptor-based efficient variable sync
- ✅ Dynamic proxy spawning with reuse
- ✅ Character controller velocity injection
- ✅ Actor state flag replication
- ✅ Action event queue infrastructure
**Phase 6 will validate whether the theoretical implementation achieves the goal of working proxy animations in-game.**
Ready to test! 🚀
+46
View File
@@ -0,0 +1,46 @@
# Documentation
Start here for Commonwealth Online project docs.
## Core
| Document | Purpose |
|---|---|
| [`setup.md`](setup.md) | Build, deploy, submodules, main-menu notes |
| [`architecture.md`](architecture.md) | Plugin, server, proxy, threading model |
| [`protocol.md`](protocol.md) | Message types and LAN discovery overview |
| [`protocol/`](protocol/) | Detailed packet and sync field reference |
| [`limitations.md`](limitations.md) | Technical limits and unsupported systems |
| [`version-targets.md`](version-targets.md) | Supported game/F4SE versions |
| [`ROADMAP.md`](ROADMAP.md) | Vertical-slice roadmap and milestones |
| [`dev-log.md`](dev-log.md) | Milestones, testing notes, next steps |
## Feature and integration guides
| Document | Purpose |
|---|---|
| [`weapon-animation-sync.md`](weapon-animation-sync.md) | Weapon animation graph reference |
| [`f4-animation-descriptor.md`](f4-animation-descriptor.md) | Humanoid animation graph variable mapping |
| [`animation-architecture-alignment.md`](animation-architecture-alignment.md) | Animation sync architecture notes |
| [`animation-sync-analysis.md`](animation-sync-analysis.md) | Animation sync problem analysis |
| [`protocol-phase2-extensions.md`](protocol-phase2-extensions.md) | Phase 2 protocol field extensions |
| [`MainMenu_Injection.md`](MainMenu_Injection.md) | Runtime main-menu Multiplayer row injection |
| [`MainMenu_Button_Injection_Guide.md`](MainMenu_Button_Injection_Guide.md) | Full main-menu injection how-to |
| [`pause-menu-vanilla-settings-plan.md`](pause-menu-vanilla-settings-plan.md) | Planned vanilla settings integration |
| [`project-comparison.md`](project-comparison.md) | Commonwealth Online vs DoxyCoSync |
## Research and reference
| Location | Purpose |
|---|---|
| [`research/`](research/) | Engine notes, sync research, related projects |
| [`reference/Interface/`](reference/Interface/) | Decompiled vanilla main-menu SWF reference (read-only) |
## Outside this folder
| Document | Purpose |
|---|---|
| [`../README.md`](../README.md) | Project overview and quick start |
| [`../changelog.md`](../changelog.md) | Change history |
| [`../server/README.md`](../server/README.md) | Relay server and dev GUI |
| [`../plugin/setup.md`](../plugin/setup.md) | Plugin build notes |
View File
-65
View File
@@ -1,65 +0,0 @@
# Roadmap
## Phase 0: Research and Setup
- [ ] Create repository structure
- [ ] Document project scope
- [ ] Document legal boundaries
- [ ] Set up Fallout 4 test profile
- [ ] Install F4SE
- [ ] Install Creation Kit
- [ ] Choose CommonLibF4 template
- [ ] Create test cell plan
## Phase 1: F4SE Plugin Bootstrap
- [ ] Create basic F4SE plugin project
- [ ] Confirm plugin loads in Fallout 4
- [ ] Create plugin log output
- [ ] Detect game version
- [ ] Read local player reference
- [ ] Read local player position
- [ ] Write position to log
## Phase 2: External Server Prototype
- [ ] Create basic local server
- [ ] Define packet format
- [ ] Support client connect/disconnect
- [ ] Assign player IDs
- [ ] Receive transform packets
- [ ] Broadcast transform packets to other clients
## Phase 3: Fallout 4 Network Connection
- [ ] Connect F4SE plugin to local server
- [ ] Send test packets from Fallout 4
- [ ] Send real player transform packets
- [ ] Receive remote transform packets
- [ ] Store remote player state safely
## Phase 4: Remote Player Representation
- [ ] Create test cell in Creation Kit
- [ ] Create placeholder remote player actor
- [ ] Spawn or place remote actor
- [ ] Move remote actor using received transform data
- [ ] Smooth remote actor movement
- [ ] Clean up actor on disconnect
## Phase 5: Basic Gameplay Sync
- [ ] Sync crouch state
- [ ] Sync sprint/walk state
- [ ] Sync weapon drawn state
- [ ] Sync basic fire event
- [ ] Sync simple health state
- [ ] Add debug UI or console commands
## Phase 6: Controlled Multiplayer Test
- [ ] Two clients in same test cell
- [ ] Both players visible
- [ ] Movement sync working
- [ ] Basic animation sync working
- [ ] Basic LAN test documented
+30
View File
@@ -9,6 +9,36 @@ failed experiments, successful tests, and next steps.
--- ---
## 2026-07-10 - Repository cleanup
### Summary
Reorganized documentation and reference assets to reduce root clutter without changing plugin, server, or game code.
### Files Changed
- `docs/README.md` (new documentation index)
- `docs/ROADMAP.md` (moved from repo root)
- `docs/protocol/` (moved from repo root `protocol/`)
- `docs/reference/Interface/` (moved from repo root `Interface/`)
- `tools/scripts/setup-ultralight-link.ps1` (moved from `scripts/`)
- Removed stale phase/milestone docs, deprecated FFDec main-menu guides, and unused `steam_interfaces.txt`
- Updated `README.md`, `build-prismaui.bat`, `tools/README.md`, `CONTRIBUTING.md`, and related doc links
### Details
- Root now holds entry-point batch scripts and core project files only; detailed protocol specs and roadmap live under `docs/`.
- Decompiled vanilla interface files remain available as read-only reference material under `docs/reference/Interface/`.
- Historical phase completion reports and deprecated SWF patching guides were removed after confirming they were superseded by current docs.
### Testing
- Not run (documentation and file moves only).
### Known Issues
- None currently known.
### Next Steps
- Continue feature work against the cleaned documentation layout.
---
## 2026-07-09 - Consumer Server CLI v1 ## 2026-07-09 - Consumer Server CLI v1
### Summary ### Summary
-39
View File
@@ -1,39 +0,0 @@
# Project Overview
Commonwealth Online is a prototype multiplayer framework experiment for Fallout 4.
The first target is not full co-op. The first target is a controlled test where two clients can connect to a local server and see each other as synced actors in a custom test cell.
## Core Idea
Fallout 4 remains the client application. A native F4SE plugin reads local player state and communicates with an external server.
The server tracks connected players and broadcasts relevant state to other clients.
A Creation Kit plugin provides test cells, placeholder actors, scripts, and controlled test content.
## Basic Flow
```text
Fallout 4 Client A
|
| local player transform
v
External Server
|
| remote player transform
v
Fallout 4 Client B
```
## Early Limitations
The first prototype should assume:
- All players are in the same cell
- No quest synchronization
- No settlement synchronization
- No VATS
- No dialogue sync
- No full inventory sync
- No support for large modlists
-232
View File
@@ -1,232 +0,0 @@
# Phase 1-3 Completion Report: TiltedEvolution Alignment
## Executive Summary
Successfully completed Phase 1-3 of the Commonwealth Online → TiltedEvolution alignment initiative. Established comprehensive architectural foundation, protocol extensions, and animation descriptor infrastructure to enable working proxy actor animations.
**Status:** Ready to proceed with Phase 4 (Dynamic Spawn).
---
## Phases Completed
### Phase 1: Blueprint & Research ✅
**Deliverables:**
- `docs/f4-animation-descriptor.md` — FO4 animation graph variable mapping + comparison with Skyrim SE
- `docs/animation-architecture-alignment.md` — Component-by-component alignment between TiltedEvolution and F4T with data flow diagrams
- `docs/animation-sync-analysis.md` — Detailed analysis of why current approach fails and how TiltedEvolution solves it
**Key Findings:**
- TiltedEvolution's architecture is compatible with FO4
- Character controller velocity injection already tested and works
- Main blockers: no descriptor tables, no action replay, no actor state flags
- Variable indices need determination via debug extraction (template provided)
**Artifacts:**
- 2 comprehensive alignment documents
- 3 architecture diagrams (mermaid)
- Comparison tables (TiltedEvolution vs F4T)
- Risk mitigation strategy documented
---
### Phase 2: State & Protocol ✅
**Deliverables:**
- Extended `RemotePlayerState` struct with:
- `uint32_t actorStateFlags1/2` — Actor state flags (combat, sneaking, animation state)
- `std::vector<RemoteActionEvent> actionEvents` — Action queue for discrete action replay
- New `RemoteActionEvent` struct with animation variable snapshots
- Updated `F4TNetworking.cpp` to parse new optional JSON fields
- Updated `server/fake_client.py` to handle and display new fields
- Created `docs/protocol-phase2-extensions.md` — Full protocol specification
**Features:**
- ✅ Fully backward compatible (missing fields = sensible defaults)
- ✅ JSON protocol extended (new optional fields)
- ✅ Server relay unchanged (transparent pass-through)
- ✅ Test client displays actor state flags in hex
- ✅ Thread-safe state storage (existing mutex preserved)
**Protocol Changes:**
```json
{
"type": "transform",
"playerId": 1,
// ... existing fields ...
// Phase 2 NEW FIELDS (optional):
"actorStateFlags1": 0x00000042,
"actorStateFlags2": 0x00000001,
"actionEvents": [
{
"type": 0,
"eventName": "ActorMovementStart",
"animationVariablesFloat": [...],
"animationVariablesBool": [...],
"animationVariablesInt": [...]
// ... more fields ...
}
]
}
```
---
### Phase 3: Animation Descriptors ✅
**Deliverables:**
- `plugin/include/F4AnimationDescriptor.h` — Class definition with full API
- `plugin/src/F4AnimationDescriptor.cpp` — Implementation with variable tables
**Features:**
- Singleton pattern with one-time initialization
- Pre-computed humanoid graph variable tables:
- **9 float variables:** Speed, direction, speedDamped, speedSampled, pitchGunAim, weaponAdjust, velocityZ, speedWalk, speedRun
- **6 bool variables:** isSprinting, isSneaking, isMoving, bMotionDriven, bInMoveState, bSprintOK
- **3 int variables:** iLeftHandType, iRightHandEquipped, iIsInSneak
- Reverse lookup maps (name → index) for diagnostics
- Public API:
- Variable name/index queries
- Bulk read/write methods: `SaveAnimationVariablesFromCache()`, `LoadAnimationVariablesToCache()`
- Thread-safe (one-time init per process)
- Graceful fallback to string-based API if indexed access unavailable
**Performance Improvement:**
- **Old (per-frame per-call):** O(n) string search × number of variables
- **New (bulk indexed):** O(1) array access + single graph manager lock
---
## Code Changes Summary
### Files Modified
- `docs/dev-log.md` — Added Phase 1-3 entries with technical details
- `plugin/include/F4TRemotePlayerState.h` — Extended struct with actor state + action queue
- `plugin/src/F4TNetworking.cpp` — Parse new JSON fields with backward compatibility
- `server/fake_client.py` — Display actor state flags
### Files Created
- `docs/f4-animation-descriptor.md` — FO4 variable mapping template
- `docs/animation-architecture-alignment.md` — Component alignment guide
- `docs/animation-sync-analysis.md` — Analysis of animation failures + solutions
- `docs/protocol-phase2-extensions.md` — Protocol specification for new fields
- `plugin/include/F4AnimationDescriptor.h` — Descriptor class definition
- `plugin/src/F4AnimationDescriptor.cpp` — Descriptor implementation
### Net Result
- **13 files** created/modified
- **~1,200 lines** of C++ code (descriptors + headers)
- **~1,500 lines** of documentation
- **~300 lines** of Python (protocol extensions + test client)
---
## Architectural Changes
### Before Phase 1-3 (Current State)
```
Local Player State → JSON → Network → Remote State
Proxy Actor (SetPosition only)
No velocity → No animations ❌
```
### After Phase 1-3 (Prepared for Phase 4+)
```
Local Player State + Actor State Flags + Actions → JSON (extended) → Network → Remote State (extended)
Proxy Actor (Dynamic spawn)
+ Velocity Injection
+ Descriptor-based sync
+ Action Replay
= Animations Work ✅
```
---
## Next Steps: Phase 4 (Dynamic Spawn)
### Phase 4.1: Implement Dynamic Proxy Spawning
- Replace pre-placed pool with dynamic `PlaceAtMe()` spawning
- Implement slot-based reuse (keep actors alive, reuse by playerId)
- Start with single proxy, add safeguards incrementally
- Keep pre-placed fallback active during testing
### Phase 4.2: Character Controller Velocity (Verify)
- Test `Actor::Move(0.016f, {0,0,0}, false)` on dynamic proxies
- Verify `SetLinearVelocityImpl()` works as expected
- Set velocity before animation sync for proper precedence
### Phase 4.3: Actor State Application
- Apply `actor→actorState.flags1/2` from remote state
- Signal animation graph FSM about combat, sneaking, etc.
- This enables state-driven graph transitions
---
## Testing Criteria (Phase 6)
- [ ] Plugin compiles with all new code
- [ ] Descriptor singleton initializes correctly (9 floats, 6 bools, 3 ints)
- [ ] Dynamic proxies spawn and move smoothly
- [ ] Character controller velocity set each frame
- [ ] Locomotion animations play (idle → walk → run → sprint)
- [ ] Actor state flags affect visuals (sneak = crouch)
- [ ] Descriptor bulk writes faster than string-based writes
- [ ] No crashes with 4+ proxies simultaneously
- [ ] Architecture aligns with TiltedEvolution patterns
---
## Decision Log
| Decision | Rationale | Impact |
|----------|-----------|--------|
| Use TiltedEvolution as blueprint | Proven in production (Skyrim SE), matches Creation Engine fundamentals | Full architectural refactor, 28-40 hours total |
| Singleton descriptor + tables | Efficient (init once, use always), extensible for creature graphs | Slightly more code, significant performance gain |
| Backward-compatible protocol | Avoid breaking existing clients/servers | New fields are optional, defaults sensible |
| Dynamic spawn instead of pool | Enables animations (proxy needs AI context), matches TiltedEvolution model | Requires testing for crash safety |
---
## Known Unknowns (Phase 1-3 Research Gaps)
1. **Exact FO4 animation variable indices** — Template created, values need debug extraction
2. **Whether `ActorMediator::ForceAction()` works the same in FO4** — Assume yes, test in Phase 5
3. **Whether dynamic proxies can have proper AI without pathfinding issues** — Assume yes, test in Phase 4
4. **Performance of descriptor bulk writes vs string-based** — Expect faster, measure in Phase 6
---
## Success Metrics (Achieved)
- ✅ Phase 1-3 all completed on schedule
- ✅ Architecture documented and aligned with TiltedEvolution
- ✅ Protocol extended without breaking compatibility
- ✅ Descriptor infrastructure ready for action replay
- ✅ No crashes or compilation errors
- ✅ Clear integration points for Phase 4-5
- ✅ Risk mitigation strategy in place
---
## Recommendations
1. **Continue to Phase 4 immediately** — Architecture is solid, no blockers identified
2. **Start with single dynamic proxy during Phase 4** — Test spawn/movement/velocity before scaling
3. **Prioritize animation debugging logs** — Will be essential for Phase 6 testing
4. **Keep pre-placed fallback active** — Safety net if dynamic spawn has issues
5. **Coordinate Phase 2.3 action capture after Phase 5 animation sync works** — Get locomotion working first
---
## Conclusion
Phases 1-3 successfully establish the foundation for TiltedEvolution-style animation synchronization in F4T. All architectural decisions are well-documented, the protocol is extensible, and descriptor infrastructure is ready. The path to working proxy actor animations is clear. Phase 4 (Dynamic Spawn) is the critical next step that will unlock character controller velocity injection and enable proper animation system integration.
**Estimated remaining work:** 20-30 hours (Phases 4-7).
**Confidence level:** High (architecture proven, integration points clear).
**Risk level:** Low-Medium (dynamic spawn needs safety testing, animation variables need verification).
-242
View File
@@ -1,242 +0,0 @@
# Phase 2 Interpolation Debugging Guide
## Problem: "Still Jerky, Not Smooth Movement"
This guide will help diagnose why interpolation isn't producing smooth movement.
---
## Quick Diagnostics
### 1. **Check If Interpolation is Even Being Called**
**Log signature to find:**
```
[Local Player ID: X] Phase 2 interpolation: remote player Y, actor=ZZZZZZZZ, smooth blending active.
```
**If this log is NOT appearing:**
- Interpolation is not being triggered
- Check: Is `distanceDrift > 0.01F`? (Remote player must be moving)
- Check: Is `a_shouldSnap == false`? (Not a teleport/snap movement)
- Check: Does `a_optSlot` exist? (Must be a runtime proxy, not fallback)
### 2. **Verify Update Rate is Sufficient**
**What's needed for smooth interpolation:**
- Updates must arrive **frequently enough** to queue waypoints
- Too infrequent updates = large gaps between waypoints = large lerps = still jerky
**Check fake client update rate:**
```bash
# In fake_client.py, look for the movement loop
# It should be sending updates at least 10-30 Hz (10-30 per second)
```
---
## Root Causes of Jerkiness
### **Root Cause 1: Not Enough Waypoints**
**Symptom:** Movement is still teleport-like, not smooth
**Reason:** Interpolation needs AT LEAST 2 waypoints
**Diagram:**
```
Bad (jerky):
Frame 1: ╔══ Position A
Frame 2: ║ ╔══ Position B (teleport)
Frame 3: ║ ║ ╔══ Position C (teleport)
Good (smooth):
Frame 1: ╔══════════════════╗ WayPoint 1 (A) queued
Frame 2: ║ Interp between ║ WayPoint 2 (B) queued, lerp A→B at 0.5
║ A and B at 25% ║
Frame 3: ║ Interp between ║ WayPoint 3 (C) queued, lerp B→C at 0.5
║ B and C at 50% ║
```
**Diagnosis:**
- Add extra logging to `ApplyRuntimeProxyTransform()`:
```cpp
LogInfoWithLocalPlayerPrefix(std::format(
"Waypoint queue size: {}, distanceDrift: {:.2f}, interpolating: {}",
a_optSlot->interpolationComponent.TimePoints.size(),
distanceDrift,
interpResult.IsInterpolating));
```
### **Root Cause 2: Update Arrival Rate Too Slow**
**Symptom:** Movement jumps happen, then freeze, then jump again
**Reason:** Remote player updates arriving slower than game frame rate
**Example:**
```
Game FPS: 60 (16ms per frame)
Update Rate: 10 Hz (100ms per update)
Result:
Frame 1-6: (100ms of frames) Interpolate slowly
Frame 7: NEW UPDATE arrives, big jump
Frame 8-13: Interpolate again
```
**Fix:** Increase fake client update frequency
```python
# In fake_client.py, change sleep duration:
time.sleep(0.033) # 30 Hz instead of slower
```
### **Root Cause 3: Alpha Calculation Wrong**
**Symptom:** Movement speed changes unexpectedly, or stalls
**Reason:** Frame counter might not be incrementing correctly
**Check the alpha calculation:**
```cpp
// In InterpolationSystem::Update()
float alpha = static_cast<float>(tickElapsed) / static_cast<float>(tickDelta);
// If tickDelta is 0 or 1, alpha calculation breaks
// tickDelta should be the FRAME DIFFERENCE between waypoints (e.g., 30-60)
```
### **Root Cause 4: Waypoint Queue Pruning Too Aggressive**
**Symptom:** Interpolation logs appear but movement still jerky
**Reason:** Queue size limited to 3, old waypoints popped too early
**Current code:**
```cpp
while (a_optSlot->interpolationComponent.TimePoints.size() > 3) {
a_optSlot->interpolationComponent.TimePoints.pop_front();
}
```
**Try increasing to 5-10 waypoints** for more buffer.
---
## Testing Strategy
### **Step 1: Add Detailed Logging**
Edit `F4TProxyActorController.cpp` in `ApplyRuntimeProxyTransform()`:
```cpp
if (a_optSlot && !a_shouldSnap && distanceDrift > 0.01F) {
static uint64_t frameCounter = 0;
frameCounter++;
// ADD THIS DEBUG LOG:
if (frameCounter % 10 == 0) { // Log every 10th frame to avoid spam
LogInfoWithLocalPlayerPrefix(std::format(
"Phase2-DEBUG: frame={}, distanceDrift={:.2f}, queueSize={}, interpolating={}",
frameCounter,
distanceDrift,
a_optSlot->interpolationComponent.TimePoints.size(),
/* will know after Update */
false));
}
// ... rest of code
}
```
### **Step 2: Monitor Log Output**
After recompiling, run fake client and watch log:
```bash
# Terminal: Watch logs in real-time
Get-Content "c:\Users\User\Documents\My Games\Fallout4\F4SE\CommonwealthOnline.log" -Wait -Tail 50 | Select-String "Phase2-DEBUG"
```
**Expected pattern (good interpolation):**
```
Phase2-DEBUG: frame=10, distanceDrift=345.62, queueSize=2, interpolating=true
Phase2-DEBUG: frame=20, distanceDrift=298.45, queueSize=2, interpolating=true
Phase2-DEBUG: frame=30, distanceDrift=251.23, queueSize=2, interpolating=true ← Smooth decrease
```
**Bad pattern (not working):**
```
Phase2-DEBUG: frame=10, distanceDrift=345.62, queueSize=1, interpolating=false
Phase2-DEBUG: frame=20, distanceDrift=1000.00, queueSize=1, interpolating=false ← Jumps!
Phase2-DEBUG: frame=30, distanceDrift=500.00, queueSize=1, interpolating=false
```
### **Step 3: Check Fake Client Update Rate**
Add logging to `fake_client.py`:
```python
last_update_time = time.time()
while True:
# ... send update ...
now = time.time()
update_interval = now - last_update_time
if update_interval > 0.05: # Log if >50ms between updates
print(f"WARNING: Long update interval: {update_interval*1000:.1f}ms")
last_update_time = now
time.sleep(0.033) # ~30 Hz
```
---
## Comprehensive Fix Checklist
- [ ] **Verify waypoints are queuing**: Add frame counter debug log
- [ ] **Confirm queue size > 1**: Should see "queueSize=2" in logs during movement
- [ ] **Check update frequency**: Fake client sending at 20-30 Hz minimum
- [ ] **Verify distanceDrift threshold**: Is `distanceDrift > 0.01F`?
- [ ] **Test with moving fake client**: Stationary player won't trigger interpolation
- [ ] **Increase waypoint buffer**: Try `queueSize > 5` instead of 3
- [ ] **Monitor alpha calculation**: Should go 0.0 → 1.0 as player moves between waypoints
---
## Quick Fix: Increase Update Frequency
**Easiest fix:** Make fake client send updates more frequently
Edit `fake_client.py`:
```python
# Find the main loop:
while True:
# ... code ...
time.sleep(0.033) # Change from 0.1 or higher to 0.033 (30 Hz)
```
Or increase queue size in `ApplyRuntimeProxyTransform()`:
```cpp
// Change from:
while (a_optSlot->interpolationComponent.TimePoints.size() > 3) {
// To:
while (a_optSlot->interpolationComponent.TimePoints.size() > 10) {
```
---
## If Still Jerky After All This
The issue might be **architectural**: Maybe F4 doesn't support sub-frame smooth movement, and we need to adjust strategy.
**Next options:**
1. **Reduce frame times via velocity injection**: Make proxies move via physics instead of SetPosition
2. **Use different lerp approach**: Accumulate delta over frames instead of tick-based
3. **Accept some jerkiness**: Design animations to hide it (blending animations during transitions)
---
## Need More Help?
Post the following in your logs:
1. Output of "Phase2-DEBUG" log lines (10 consecutive)
2. Fake client update interval timing
3. FPS you're getting in-game
4. Distance between waypoints in the logs
This will help diagnose the exact cause.
-365
View File
@@ -1,365 +0,0 @@
# Phase 2: Interpolation System Testing Guide
## Overview
Phase 2 tests the waypoint-based smooth movement interpolation system. This replaces direct position application with time-based lerp between waypoints, resulting in smoother remote player movement.
**Prerequisites:**
- F4T plugin built with interpolation system (just completed ✓)
- Fallout 4 running with F4SE
- Network relay server running (`python server.py`)
- Fake client ready (`python server/fake_client.py`)
---
## Architecture Review
Before testing, understand what we're testing:
### Current System (Pre-Phase 2)
```
Remote Player Update
GetRuntimeProxyVisibleTargetPosition()
targetPosition = direct network position
SetPosition(targetPosition) ← IMMEDIATE, no lerp
Result: Jittery/choppy movement on low update rates
```
### New System (Phase 2)
```
Remote Player Update
GetRuntimeProxyVisibleTargetPosition()
AddWaypoint(targetPosition, angleZ, currentTick) → InterpolationComponent
InterpolationSystem::Update(currentTick)
Lerp between waypoints if tick is between them
SetPosition(interpolatedPosition) ← SMOOTH, tick-based
Result: Smooth movement even on low update rates
```
---
## Testing Phase 2.1: Interpolation System Unit Test
### Goal
Verify interpolation math works correctly before testing in-game.
### Test: Manual Interpolation Check
Create a simple test script (`test_interpolation.py`):
```python
# Pseudo-code showing what Phase 2 does
# Position at tick 100: (1000, 2000, 500)
# Position at tick 200: (1100, 2050, 550)
# At tick 150 (halfway):
# alpha = (150 - 100) / (200 - 100) = 0.5
# interpolated_x = 1000 + (1100 - 1000) * 0.5 = 1050
# interpolated_y = 2000 + (2050 - 2000) * 0.5 = 2025
# interpolated_z = 500 + (550 - 500) * 0.5 = 525
# Result: (1050, 2025, 525) ← smooth midpoint
```
**Expected behavior:** Movement is linear blend between waypoints.
---
## Testing Phase 2.2: In-Game Setup
### Setup Step 1: Start Relay Server
```bash
cd f:\Repos\Commonwealth-Online\server
python server.py
```
Expected output:
```
Server listening on 127.0.0.1:7777
Waiting for connections...
```
### Setup Step 2: Start Fake Client
In a new terminal:
```bash
cd f:\Repos\Commonwealth-Online\server
python fake_client.py
```
Expected output:
```
Connecting to server...
Connected successfully
Fake player registered with ID: <player_id>
```
### Setup Step 3: Launch Fallout 4
1. Start Fallout 4 with F4SE
2. Load into a game with open space (avoid dungeons)
3. Check console for F4T startup messages
Expected log output:
```
[Local Player ID: X] F4T Plugin initialized
[Local Player ID: X] Proxy controller ready
```
---
## Testing Phase 2.3: Basic Interpolation Test
### Test: Remote Player Walks in Circle
This verifies waypoint buffering and interpolation.
**Setup:**
1. Have fake client move in a small circle around you
2. Watch the proxy actor move
**Expected Behavior (PRE-Phase 2):**
- Proxy position updates in discrete jumps
- Movement appears jittery/choppy
- Proxy teleports between waypoints
**Expected Behavior (POST-Phase 2):**
- Proxy moves smoothly
- Movement is continuous, not jerky
- Smooth arc instead of sharp jumps
**How to Verify:**
1. Run fake client for 30 seconds with slow movement
2. Observe proxy actor
3. Compare smoothness to pre-Phase 2 behavior
**Log Indicators:**
```
[Local Player ID: 0] First smoothed runtime proxy movement for remote player X: actor=FORMID, alpha=0.15.
```
This log should appear once per remote player.
---
## Testing Phase 2.4: Movement Speed Variations
### Test: Fast vs Slow Movement
**Objective:** Verify interpolation works across movement speeds.
**Test Case 1: Slow Movement**
- Fake client walks slowly (1-2 units/sec)
- Expected: Smooth continuous movement
- Should NOT have position snapping
**Test Case 2: Fast Movement**
- Fake client sprints (100+ units/sec)
- Expected: Fast smooth movement
- No lag or skipping
**Test Case 3: Teleport**
- Fake client teleports 500 units away
- Expected: Proxy snaps (shouldSnap=true for teleport movement type)
- Movement type check happens first, no interpolation
---
## Testing Phase 2.5: Multiple Remote Players
### Test: Interpolation with 2-4 Remote Players
**Setup:**
1. Start 2-4 fake clients
2. Each sends unique movement patterns
3. Observe all proxies
**Expected Behavior:**
- Each proxy interpolates independently
- No interaction/interference between proxies
- Each has its own InterpolationComponent
- Smooth movement for all
**Performance Check:**
1. Monitor FPS with 4 remote players
2. Should be similar to Phase 1 (baseline)
3. Interpolation adds minimal CPU load (just lerp math)
**Command to simulate:**
```bash
# Terminal 1: Start main relay
python server.py
# Terminal 2-5: Start 4 fake clients
python fake_client.py
python fake_client.py
python fake_client.py
python fake_client.py
```
---
## Testing Phase 2.6: Waypoint Queue Management
### Test: Verify Waypoint Cleanup
**Objective:** Ensure old waypoints are cleaned up, not accumulated.
**How to Check:**
1. Run fake client for 2 minutes straight
2. Monitor memory usage
3. Should be stable (not growing)
**What's Happening:**
```
Tick 100: Add waypoint
Tick 101-150: Lerp between waypoint 0 and 1
Tick 151: Pop waypoint 0 (cleanup!)
Tick 151: Add new waypoint
Tick 152-200: Lerp between waypoint 0 and 1 (still 2 max)
```
The InterpolationSystem::Update() automatically pops old waypoints when they're consumed.
---
## Testing Phase 2.7: Rotation Interpolation
### Test: Verify Smooth Rotation
**Objective:** Test angle lerp with wrap-around handling.
**Test Case 1: Normal Rotation**
- Remote player rotates from 0° to 90°
- Expected: Smooth rotation from 0° → 45° → 90°
**Test Case 2: Wrap-Around**
- Remote player rotates from 350° to 10° (crossing 0°)
- Expected: Shortest path rotation (350° → 0° → 10°), not 350° → 180° → 10°
- Our `LerpRotation()` handles this
**Visual Check:**
- Watch proxy heading as it turns
- Should be smooth, not jerky
- Should take shortest angular path
---
## Testing Phase 2.8: Integration with Animation Sync
### Test: Interpolation + Descriptor-Based Animation
**Setup:**
1. Ensure Phase 1 (descriptor-based animation) is working
2. Run Phase 2 interpolation in parallel
3. Fake client walks around you
**Expected Behavior:**
- Remote player position interpolates smoothly
- Remote player animation (Speed, isSprinting) syncs correctly
- No conflicts between systems
**Verification:**
```
[Local Player ID: 0] Runtime proxy animation sync initial for remote player X:
moving=true, sprinting=false, graphSpeed=55.0, direction=0.123
```
This should still appear alongside interpolation.
---
## Testing Checklist
- [ ] **Unit Test**: Lerp math is correct (waypoint positions smooth)
- [ ] **Single Player**: Fake client walks, proxy moves smoothly
- [ ] **Slow Movement**: Proxy glides smoothly at 1-2 units/sec
- [ ] **Fast Movement**: Proxy glides smoothly at 100+ units/sec
- [ ] **Multiple Players**: 2-4 proxies move smoothly independently
- [ ] **Memory**: Stable after 2+ minutes (no memory growth)
- [ ] **Rotation**: Proxy heading rotates smoothly
- [ ] **Wrap-Around**: Rotation handles 0°↔360° correctly
- [ ] **Integration**: Works with Phase 1 animation sync
- [ ] **Snapping**: Teleports still snap (movement type check first)
---
## Debugging: Common Issues & Fixes
### Issue: Proxy Still Jerky After Phase 2
**Cause:** Interpolation not being called
**Fix:**
1. Check that `AddWaypoint()` is being called
2. Verify `Update()` is called before `SetPosition()`
3. Check that `shouldSnap` isn't overriding interpolation
### Issue: Proxy Moves Too Slowly
**Cause:** Alpha blend factor too small
**Fix:**
1. Increase waypoint update rate (more frequent updates = smoother)
2. Check tick calculation (verify currentTick is advancing)
### Issue: Memory Grows Over Time
**Cause:** Waypoints not being popped
**Fix:**
1. Verify `Update()` is cleaning up old waypoints
2. Check that TimePoints.pop_front() is being called
### Issue: Rotation Wraps Incorrectly
**Cause:** LerpRotation() not handling 0°/360° boundary
**Fix:**
- This is handled in our implementation
- If still wrong, check angle units (radians vs degrees)
---
## Next Steps After Testing
1. **If interpolation works:** Move to Phase 3 or other features
2. **If issues found:** Document in dev-log.md and fix
3. **Performance baseline:** Record FPS with 1, 2, 4 remote players
---
## Quick Start Commands
```bash
# Terminal 1: Start relay server
cd f:\Repos\Commonwealth-Online\server
python server.py
# Terminal 2: Start fake client (single remote player)
cd f:\Repos\Commonwealth-Online\server
python fake_client.py
# In-game: Launch F4T and observe proxy movement
```
---
## Expected Logs for Phase 2
When interpolation is active, look for:
```
[Local Player ID: 0] First smoothed runtime proxy movement for remote player 1: actor=0x14003ED8, alpha=0.15.
[Local Player ID: 0] Moved runtime proxy actor 0x14003ED8 from remote player 1 state for the first time: X=1234.56, Y=2345.67, Z=-100.00, AngleZ=1.570, flags1=00000000, flags2=00000000.
```
These confirm the proxy is spawned and moving smoothly.
-177
View File
@@ -1,177 +0,0 @@
# Phase 6 Quick Start Checklist
## Before You Start
- [ ] All Phases 1-5 code committed to git
- [ ] F4T plugin builds without errors
- [ ] F4SE installed in Fallout 4
- [ ] Server relay running (`python server/server.py`)
- [ ] Ready to launch Fallout 4 with F4SE
## Test Execution Order
### Critical Path (30 minutes)
1. **[5 min] Test 1: Proxy Spawning**
- Start game, load F4TTestCell01
- Connect fake client
- [ ] Proxy appears near player
- [ ] No crashes
- **Result:** PASS / FAIL
2. **[5 min] Test 2: Movement**
- Move fake client position
- [ ] Proxy smoothly moves to new position
- [ ] No jittering/snapping
- **Result:** PASS / FAIL
3. **[10 min] TEST 3 - CRITICAL: Animations**
- Fake client: stand still → should see idle
- Fake client: walk speed → should see walk animation
- Fake client: run speed → should see run animation
- Fake client: sprint speed → should see sprint animation
- [ ] At least idle/walk/run animations visible
- **Result:** PASS / FAIL / PARTIAL
- **If FAIL:** Debug with console logs
4. **[5 min] Test 4: Sneak**
- Fake client: activate sneak
- [ ] Proxy crouches
- **Result:** PASS / FAIL / PARTIAL
5. **[5 min] Test 5: Multiple Proxies**
- Connect 3 fake clients (3 proxies total)
- All moving simultaneously
- [ ] All animate correctly
- [ ] No crashes
- **Result:** PASS / FAIL
### If Test 3 FAILS (Animations not playing)
**Debug Checklist (10 minutes):**
1. [ ] Check console logs for velocity being set
- Search: `ApplyRuntimeProxyTransform`
- Should show character controller access
2. [ ] Check animation graph manager available
- Search: `animation graph manager`
- Should NOT show "unavailable" messages
3. [ ] Check actor state flags
- Search: `flags1=`
- Should show valid hex values
4. [ ] Check Speed variable is changing
- Search: `graphSpeed=`
- Should see values > 0 when moving
5. [ ] Manual test: Set Speed directly in console
- If manual setting works → indices correct, velocity issue
- If manual setting doesn't work → index problem
**If still failing:** Document issue and proceed to Phase 6.3 iteration
## Key Logging Commands
### View Real-Time Logs
```powershell
# In separate terminal, tail latest logs
Get-Content "Documents\My Games\Fallout4\Logs\*.log" -Wait
```
### Search Logs for Specific Info
```powershell
# Proxy spawn
Select-String "SpawnDynamicProxyActor" (Get-ChildItem "Documents\My Games\Fallout4\Logs\*")
# Animations
Select-String "animation sync" (Get-ChildItem "Documents\My Games\Fallout4\Logs\*")
# Errors
Select-String "WARNING\|ERROR" (Get-ChildItem "Documents\My Games\Fallout4\Logs\*")
```
## Expected Console Log Patterns
### Good (Animations Working)
```
[Local Player ID: 0] SpawnDynamicProxyActor: Spawned proxy actor 0xABCD1234 for remote player 1
[Local Player ID: 0] Assigned dynamically spawned proxy 0xABCD1234 to remote player 1
[Local Player ID: 0] First smoothed runtime proxy movement for remote player 1: actor=0xABCD1234, alpha=0.15
[Local Player ID: 0] ApplyRuntimeProxyTransform: Proxy 0xABCD1234 has AIProcess: true
[Local Player ID: 0] Runtime proxy animation sync initial for remote player 1: moving=true, sprinting=false, graphSpeed=55.0
```
### Bad (Animations NOT Working)
```
[Local Player ID: 0] animation graph manager unavailable
[Local Player ID: 0] Failed to load animation variables for remote player 1
[Local Player ID: 0] Proxy 0xABCD1234 has NO AIProcess
```
## Performance Expectations
| Metric | Expected | Alert If |
|--------|----------|----------|
| Proxy spawn time | < 500ms | > 1 second |
| Per-proxy update | < 1ms | > 5ms |
| Frame rate | 60+ fps | < 30 fps with 1 proxy |
| Animation smooth | No stutter | Visible jitter |
## Results Template
Copy this after testing:
```
## Phase 6 Test Results - [DATE]
### Tests
- Test 1 (Spawning): PASS / FAIL
- Test 2 (Movement): PASS / FAIL
- Test 3 (Animations): PASS / FAIL / PARTIAL
- Test 4 (Sneak): PASS / FAIL / PARTIAL
- Test 5 (Multiple): PASS / FAIL
### Issues Found
1. <Issue>
- Severity: Critical / Major / Minor
- Fix: <action needed>
### Next Action
- [ ] PASS ALL → Proceed to Phase 7
- [ ] PARTIAL → Iterate Phase 6.3 (tune)
- [ ] FAIL → Debug and retest
```
## Common Fixes
### Animations not playing
- **Try:** Increase velocity scale (multiply by 1.2x)
- **Try:** Check animation variable indices in F4AnimationDescriptor
- **Try:** Enable debug logging for Speed variable
### Proxy doesn't move smoothly
- **Try:** Reduce lerp alpha (currently 0.15)
- **Try:** Increase update frequency (more network packets)
- **Try:** Check for network lag
### Multiple proxies crash
- **Try:** Reduce from 4 to 2 proxies
- **Try:** Check for memory leaks in action queue
- **Try:** Verify proxy pool cleanup on disconnect
## Success = All PASS
When you see:
1. ✅ Proxy spawns
2. ✅ Proxy moves smoothly
3. ✅ Proxy animates (idle/walk/run/sprint)
4. ✅ Multiple proxies work
5. ✅ No crashes
**Then Phase 6 is COMPLETE and Phase 7 ready!**
-426
View File
@@ -1,426 +0,0 @@
# 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 <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):**
```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: <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
+1 -1
View File
@@ -96,7 +96,7 @@ This document describes the Phase 2 protocol extensions to support actor state f
## World State Packet ## World State Packet
Host-authoritative time and weather sync uses a separate `worldState` packet. Host-authoritative time and weather sync uses a separate `worldState` packet.
Full field definitions live in [`protocol/world-state.md`](../protocol/world-state.md). Full field definitions live in [`protocol/world-state.md`](protocol/world-state.md).
```json ```json
{ {
+1 -1
View File
@@ -63,4 +63,4 @@ The protocol should be testable outside Fallout 4 before it is used inside the F
`transform` packets carry position, movement state, optional `equippedItems` `transform` packets carry position, movement state, optional `equippedItems`
apparel snapshots, and optional `appearance` snapshots for best-effort proxy apparel snapshots, and optional `appearance` snapshots for best-effort proxy
body/face visuals. The canonical field list and compatibility rules live in body/face visuals. The canonical field list and compatibility rules live in
[`protocol/packets.md`](../protocol/packets.md). [`protocol/packets.md`](protocol/packets.md).
+7
View File
@@ -0,0 +1,7 @@
# Vanilla Interface reference
Decompiled Fallout 4 interface assets kept for **reading and research only**.
Commonwealth Online injects the main-menu **Multiplayer** row at runtime from C++. Do **not** re-import or deploy patched SWFs from this folder.
See [`../../MainMenu_Injection.md`](../../MainMenu_Injection.md) for the supported approach.
-23
View File
@@ -1,23 +0,0 @@
SteamClient017
SteamClient020
SteamGameServer014
SteamGameServerStats001
SteamUser021
SteamFriends017
SteamUtils010
SteamMatchMaking009
SteamMatchMakingServers002
STEAMUSERSTATS_INTERFACE_VERSION012
STEAMAPPS_INTERFACE_VERSION008
SteamNetworking006
STEAMREMOTESTORAGE_INTERFACE_VERSION016
STEAMSCREENSHOTS_INTERFACE_VERSION003
STEAMHTTP_INTERFACE_VERSION003
STEAMUGC_INTERFACE_VERSION016
STEAMAPPLIST_INTERFACE_VERSION001
STEAMMUSIC_INTERFACE_VERSION001
STEAMMUSICREMOTE_INTERFACE_VERSION001
STEAMHTMLSURFACE_INTERFACE_VERSION_005
STEAMINVENTORY_INTERFACE_V003
SteamController008
STEAMVIDEO_INTERFACE_V002
+11 -8
View File
@@ -1,14 +1,17 @@
# Tools # Tools
This folder is for helper tools and development scripts. Helper utilities and development scripts for Commonwealth Online.
Possible future tools: ## Scripts
- Build scripts | Script | Purpose |
- Packaging scripts |---|---|
- Log parsers | [`scripts/setup-ultralight-link.ps1`](scripts/setup-ultralight-link.ps1) | Junction-link Ultralight SDK for PrismaUI builds (called by `build-prismaui.bat`) |
- Packet replay tools | [`restore-vanilla-mainmenu.ps1`](restore-vanilla-mainmenu.ps1) | Restore vanilla `MainMenu.swf` from game archives |
- Test client scripts | [`extract_ba2.py`](extract_ba2.py) | BA2 archive extraction helper |
- Development environment helpers
## Reference assets
Decompiled vanilla interface reference files live under [`docs/reference/Interface/`](../docs/reference/Interface/). Do not deploy patched SWFs from that folder.
Do not place Fallout 4 game files or proprietary tools in this folder. Do not place Fallout 4 game files or proprietary tools in this folder.
@@ -5,7 +5,7 @@ param(
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$repoRoot = Split-Path -Parent $scriptDir $repoRoot = Split-Path -Parent (Split-Path -Parent $scriptDir)
if ([string]::IsNullOrWhiteSpace($SdkPath)) { if ([string]::IsNullOrWhiteSpace($SdkPath)) {
$SdkPath = Join-Path $repoRoot "ThirdParty\Ultralight-SDK" $SdkPath = Join-Path $repoRoot "ThirdParty\Ultralight-SDK"