Character Appearance Phase 1 Done
Bump appearance payloads to version 2 and add `morphRegions` and `facialBoneMorphs` capture, serialization, and proxy application. Also fix head-part syncing when sender and proxy counts differ by reallocating the proxy array instead of deferring the whole list, and update the Python harness and protocol docs to match.
This commit is contained in:
@@ -9,6 +9,73 @@ failed experiments, successful tests, and next steps.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-30 - Head-Part Count Mismatch Fix (Hair Sync)
|
||||
|
||||
### Summary
|
||||
After Phase 1 morph sync, two-client testing showed an asymmetric result: Client 2's proxy of Client 1 got morphs and hair, but Client 1's proxy of Client 2 got morphs but no hair. The log showed `Deferred head-part appearance for remote player 2; proxy count=12 packet count=14`. The apply code only overwrote head parts when the proxy base count exactly matched the sender's count, otherwise it deferred the entire head-part list (so hair, eyes, brows, etc. all stayed default). Player 2 had 14 head parts vs the proxy base's 12, so nothing applied; Player 1 happened to have 12, matching the base, so it worked the other direction. This is a pre-existing limitation, not a Phase 2 (tint) concern.
|
||||
|
||||
### Files Changed
|
||||
- `plugin/src/F4TProxyActorController.cpp`
|
||||
- `changelog.md`
|
||||
- `docs/dev-log.md`
|
||||
|
||||
### Details
|
||||
- `ApplyProxyAppearanceFromRemoteState` now resolves all sender head parts first (skipping any unresolved local forms), then either overwrites in place when the count matches or reallocates `npc->headParts` with `RE::calloc` and updates `npc->numHeadParts` when it differs.
|
||||
- The previous head-part array is intentionally not freed, to avoid touching memory that may be shared with the base template or an alternate head-part list. Count-changing appearance updates are rare and deduped, so the bounded leak is acceptable for the prototype.
|
||||
- The apply success log now reports `headParts=applied/sent` instead of just the sent count, which previously masked the deferral.
|
||||
|
||||
### Testing
|
||||
- Static review and linter only; no in-game run yet.
|
||||
- Recommended manual check: reproduce the prior two-client scenario (characters with differing head-part counts) and confirm both proxies now show hair, with a log line like `headParts=14/14` and no `Deferred head-part appearance` warning.
|
||||
- Watch for any head/face instability after the array reallocation across repeated appearance changes.
|
||||
|
||||
### Known Issues
|
||||
- Head parts, morphs, and tints are still written to the proxy's base `TESNPC`; with 3+ remote players sharing a single proxy base on one client, appearances could clobber. Not exercised by the current two-player test.
|
||||
- Skin colour/tint sync still pending Phase 2.
|
||||
|
||||
### Next Steps
|
||||
- Continue with Phase 2 (tint/skin colour) per the appearance plan.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-30 - Facial Morph Appearance Sync (Appearance v2, Phase 1)
|
||||
|
||||
### Summary
|
||||
Investigated a report that synced proxies were "just the default proxy", with skin colour, facial hair, and some facial morphs not transferring. Root cause: `CaptureLocalAppearance` only copied a subset of `TESNPC` face data. Three face-defining members were never captured or applied: `morphRegionSliderValues`, `facialBoneRegionSliderValues`, and `tintingData`. The currently-synced `morphSliderValues` is only a partial morph set, so only some morphs transferred. This change is Phase 1 of a phased fix: it adds the two safe, plain-data morph payloads. Skin colour/tint reconstruction (`tintingData`) is deferred to Phase 2 because it requires high-risk game-thread reconstruction of polymorphic `BGSCharacterTint` entries.
|
||||
|
||||
### Files Changed
|
||||
- `plugin/include/F4TRemotePlayerState.h`
|
||||
- `plugin/src/main.cpp`
|
||||
- `plugin/src/F4TNetworking.cpp`
|
||||
- `plugin/src/F4TProxyActorController.cpp`
|
||||
- `protocol/packets.md`
|
||||
- `server/fake_client.py`
|
||||
- `server/fake_player.py`
|
||||
- `changelog.md`
|
||||
- `docs/dev-log.md`
|
||||
|
||||
### Details
|
||||
- Bumped the appearance payload `version` default to 2. New fields are optional/additive; receivers tolerate their absence and keep existing proxy morph data.
|
||||
- Added `morphRegions` (flat array of region slider floats) and `facialBoneMorphs` (`{ id, position[3], rotation[3], scale[3] }`) to the appearance snapshot.
|
||||
- Capture reads `npc->morphRegionSliderValues` (`BSTArray<float>`) and `npc->facialBoneRegionSliderValues` (`BSTHashMap<uint32, BGSCharacterMorph::Transform>`) with null guards.
|
||||
- Apply allocates/clears the matching `TESNPC` containers on the proxy and fills them, then reuses `RefreshProxyAfterAppearanceChange` to trigger the existing head/face 3D refresh. Followed the existing `new`-on-null pattern used for `morphSliderValues`.
|
||||
- Equality checks in both `AreAppearanceStatesEqual` copies (main.cpp and the proxy controller) compare the new fields so changes still trigger resend/reapply.
|
||||
|
||||
### Testing
|
||||
- Static review only so far; no in-game run yet.
|
||||
- Recommended: `python -m py_compile server\fake_client.py server\fake_player.py` for the harness changes.
|
||||
- Recommended manual check: run the Python server, connect two Fallout 4 instances, and confirm Client 1's proxy of Client 2 now picks up advanced face-shape morphs that previously did not transfer, with no new appearance warnings in `CommonwealthOnline.log`.
|
||||
- Backwards compatibility: confirm version 1 packets (without `morphRegions`/`facialBoneMorphs`) still apply without error.
|
||||
|
||||
### Known Issues
|
||||
- Skin colour, complexion, and beard shade still will not sync until Phase 2 (`tintingData` reconstruction) lands.
|
||||
- In-game confirmation of the new morph fields is still needed.
|
||||
|
||||
### Next Steps
|
||||
- Phase 2: capture `PlayerCharacter::tintingData`, resolve the proxy race's tint templates via `TESRace::FaceRelatedData::tintingTemplate`, and reconstruct `BGSCharacterTint` entries on the proxy to fix skin colour and beard shade.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-29 - Late-Join Appearance Snapshot Fix
|
||||
|
||||
### Summary
|
||||
|
||||
Reference in New Issue
Block a user