Add new Papyrus scripts (CoSync.psc, CoSyncPlayer.psc, CoSyncQuest.psc) providing native bindings and quest/player proxy logic for networking: connection/session APIs, entity management, world/weather/workshop/companion sync, consumable/pipboy/door/power-armor events, and proxy animation/initialization handlers. Refactor the proxy actor controller (F4TProxyActorController.cpp) to support dynamic/runtime proxy spawning and improved lifecycle/visibility handling: change proxy base/form IDs to COPlayerProxy/CommonwealthOnline, add process-list actor lookup, spawn helpers, play-space/cell checks, 3D visibility refresh, ActorHandle usage, and spawn mutexes and globals for safer spawning. Update docs and setup (architecture.md, limitations.md, plugin/setup.md) to describe global dynamic spawn behavior, max runtime proxies (kMaxRuntimeProxyActors = 4), and validation checklist; update launch-two-fallout4.bat to show instance log locations. Misc: small tweaks to logging and debug flags to gate diagnostics.
5.5 KiB
Player Sync
Player synchronization is the first major technical goal for Commonwealth Online. The current implementation is still a local networking prototype.
Current Implemented Flow
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 reads a copied snapshot of this remote-player state and dynamically spawns/moves runtime proxy actors in the local player's current loaded cell. The networking thread still does not touch Fallout 4 actors or references. If a remote player is not in the same cell/worldspace, the controller holds that player's proxy at a hidden in-cell position instead of leaving it at the last visible location.
Current Remote Player State Model
The plugin and fake client store remote players by playerId.
Each remote player state entry tracks:
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
welcomepackets and stores its assignedplayerId. - 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
disconnectpackets and removes remote player state. - The server assigns incrementing
playerIdvalues. - The server sends
welcomepackets. - The server adds
playerIdandserverTimeto transform packets. - The server broadcasts transform packets to other connected clients.
- The fake client stores remote player state by
playerId. - The server broadcasts
disconnectpackets. - 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, andteleporttransforms 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 include movement state data (
isMoving,movementSpeed,isSprinting,isSneaking,isJumping,weaponDrawn). - The game-thread proxy controller applies confirmed Havok animation graph variables to runtime proxy actors from that remote state (locomotion, sneak, jump, weapon drawn). Transform position/heading sync is unchanged.
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
CommonwealthOnline.logremains 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.
Runtime proxy actors are dynamically spawned per remote playerId in the local
player's current loaded cell (see architecture). Remote players in a different
cell are held at a hidden in-cell position until the local player enters their
cell. Full animation graph replication is not implemented; only curated graph
variable writes drive proxy locomotion visuals.
Planned Later
- Increase concurrent proxy cap beyond four players per client
- Cross-cell actor transfer without respawn (if respawn proves insufficient)
Not Required Yet
- Full animation graph sync
- Combat sync
- Inventory sync
- Quest sync
- Dialogue sync
- Settlement sync
- Accurate physics sync
- Public networking or matchmaking