Add a temporary in-cell holding fallback for the single placed proxy actor when no valid same-cell remote player is available. Introduces kProxyHiddenHoldingPosition, ProxyLifecycleState, RemotePlayerSelection, MoveProxyToHoldingPosition and RestoreProxyForRemotePlayer, plus selection/state-tracking and throttled logs. The controller now moves the proxy to the hidden position on disconnect, disappearance, or cell-mismatch and snaps it back when a valid same-cell remote appears. Documentation and dev log updated to describe the lifecycle and rationale (docs/architecture.md, docs/dev-log.md, protocol/player-sync.md).
135 lines
5.1 KiB
Markdown
135 lines
5.1 KiB
Markdown
# Player Sync
|
|
|
|
Player synchronization is the first major technical goal for Fallout 4 Together.
|
|
The current implementation is still a local networking prototype.
|
|
|
|
## Current Implemented Flow
|
|
|
|
```text
|
|
Fallout 4 Plugin ↔ Local Python Server ↔ Other Clients
|
|
↓
|
|
Plugin Remote Player State
|
|
```
|
|
|
|
The Fallout 4 plugin currently reads the local player's transform and sends it
|
|
to the local Python server. Normal movement sends are throttled separately from
|
|
local movement logs: while the player is moving, the plugin targets roughly
|
|
10 Hz and skips sends until position or rotation changes meaningfully. The
|
|
server assigns a `playerId`, adds `serverTime`, and broadcasts transform packets
|
|
to other connected clients.
|
|
|
|
The Fallout 4 plugin also receives server packets on a background networking
|
|
thread. It stores its assigned `playerId`, stores remote transform state by
|
|
remote `playerId`, and removes remote state when disconnect packets arrive.
|
|
`server/fake_client.py` remains a lightweight test receiver for the same packet
|
|
lifecycle.
|
|
|
|
The plugin's game-thread proxy actor controller can now read a copied snapshot
|
|
of this remote-player state and move the single placed test proxy actor
|
|
`F4TProxyRemotePlayer01REF` in `F4TTestCell01`. The networking thread still does
|
|
not touch Fallout 4 actors or references. If no valid same-cell remote player is
|
|
available, the controller moves the placed proxy to a hidden holding position
|
|
inside the same test cell instead of leaving it frozen at the last represented
|
|
position.
|
|
|
|
## Current Remote Player State Model
|
|
|
|
The plugin and fake client store remote players by `playerId`.
|
|
|
|
Each remote player state entry tracks:
|
|
|
|
```text
|
|
playerId
|
|
x
|
|
y
|
|
z
|
|
angleZ
|
|
movementType
|
|
cellId
|
|
worldspaceId
|
|
clientTime
|
|
serverTime
|
|
isMoving
|
|
isSprinting
|
|
isSneaking
|
|
isJumping
|
|
weaponDrawn
|
|
movementSpeed
|
|
lastReceivedLocalTime
|
|
```
|
|
|
|
Required transform packet fields are `type`, `playerId`, `x`, `y`, `z`,
|
|
`angleZ`, and `cellId`. `worldspaceId`, `movementType`, `clientTime`, and
|
|
`serverTime` are optional; interior test cells may omit `worldspaceId`.
|
|
Movement state fields are also optional and default to not moving, not
|
|
sprinting, not sneaking, not jumping, weapon holstered, and speed `0.0` when
|
|
missing.
|
|
|
|
This model proves the data shape and lifecycle before spawning remote actors.
|
|
For the current visual milestone, the controller represents only one remote
|
|
player and chooses the lowest available `playerId` if more than one remote
|
|
player exists.
|
|
|
|
## Implemented
|
|
|
|
- The plugin sends local player transform packets.
|
|
- Normal transform sends are independent from movement logging and are
|
|
thresholded to avoid packet-per-frame traffic.
|
|
- The plugin receives `welcome` packets and stores its assigned `playerId`.
|
|
- The plugin receives broadcast transform packets.
|
|
- The plugin ignores transform packets for its own assigned `playerId`.
|
|
- The plugin stores remote player state by `playerId`.
|
|
- The plugin receives `disconnect` packets and removes remote player state.
|
|
- The server assigns incrementing `playerId` values.
|
|
- The server sends `welcome` packets.
|
|
- The server adds `playerId` and `serverTime` to transform packets.
|
|
- The server broadcasts transform packets to other connected clients.
|
|
- The fake client stores remote player state by `playerId`.
|
|
- The server broadcasts `disconnect` packets.
|
|
- The fake client removes disconnected remote players from its state table.
|
|
- The plugin moves the single placed test proxy actor from a thread-safe
|
|
remote-player snapshot on the game-thread update path.
|
|
- Normal proxy movement is smoothed toward the latest received target, while
|
|
`cell_change`, `worldspace_change`, and `teleport` transforms snap directly to
|
|
avoid slow movement across large discontinuities.
|
|
- The game-thread proxy controller holds the single proxy at a hidden in-cell
|
|
position when the represented player disconnects, disappears, or leaves the
|
|
local test cell, then snaps back to a valid same-cell remote player before
|
|
resuming smoothing.
|
|
- Transform packets now include basic movement state data for future animation
|
|
work, but the proxy actor does not apply animations from that state yet.
|
|
|
|
## Transform Cadence
|
|
|
|
Normal local movement currently uses three separate rates:
|
|
|
|
- Network sends target roughly 10 Hz while the player is moving.
|
|
- Sends are skipped until position changes by about 3 game units or rotation
|
|
changes by about 0.02 radians.
|
|
- Local movement logs stay much slower, around once per second, so
|
|
`Fallout4Together.log` remains readable.
|
|
|
|
`cell_change`, `worldspace_change`, and `teleport` movement types bypass the
|
|
normal send interval and are sent immediately. The receiving plugin still stores
|
|
remote transform state on the networking thread and moves actors only from the
|
|
game-thread proxy controller.
|
|
|
|
No Fallout 4 remote actor is dynamically spawned yet.
|
|
No animation graph sync or animation application is implemented yet.
|
|
|
|
## Planned Later
|
|
|
|
- Add one proxy actor per remote player after the single-proxy test is stable.
|
|
- Dynamically spawn remote actors only after placed-proxy movement is stable.
|
|
|
|
## Not Required Yet
|
|
|
|
- Full animation graph sync
|
|
- Combat sync
|
|
- Inventory sync
|
|
- Quest sync
|
|
- Dialogue sync
|
|
- Settlement sync
|
|
- Accurate physics sync
|
|
- Public networking or matchmaking
|