Add Papyrus sync scripts and proxy spawn refactor
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.
This commit is contained in:
+16
-8
@@ -115,14 +115,22 @@ Use this checklist for the first plugin test:
|
||||
* [ ] Plugin log shows `[LocalPlayerId=N] Assigned server playerId: N`
|
||||
* [ ] Plugin logs prefixed remote player updates from another connected client
|
||||
* [ ] Plugin logs prefixed remote player removal after a disconnect
|
||||
* [ ] `Fallout4Together_Test.esp` is enabled
|
||||
* [ ] `coc F4TTestCell01` places the local player in the test cell
|
||||
* [ ] `F4TProxyRemotePlayer01REF` resolves in the test cell
|
||||
* [ ] With two Fallout 4 instances in `F4TTestCell01`, each instance moves its
|
||||
local proxy to the other player's networked position
|
||||
* [ ] `CommonwealthOnline.esp` is enabled (provides `COPlayerProxy` actor base, local FormID `001733`)
|
||||
* [ ] With two Fallout 4 instances in the same cell, each instance spawns a dynamic
|
||||
proxy at the other player's networked position
|
||||
* [ ] Optional regression: `coc F4TTestCell01` with `kEnablePrePlacedProxyPool` enabled
|
||||
* [ ] Optional regression: `F4TProxyRemotePlayer01REF` resolves when placed fallback flag is on
|
||||
|
||||
### Global dynamic spawn validation
|
||||
|
||||
* [ ] Two clients in the same vanilla interior (e.g. Sanctuary house) see each other's proxies
|
||||
* [ ] Two clients in the Commonwealth exterior in the same loaded area see proxies
|
||||
* [ ] Remote player in a different cell: proxy held hidden, not visible
|
||||
* [ ] Local player walks into remote player's cell: proxy spawns at remote position
|
||||
* [ ] Local player leaves a cell with active proxies: no orphaned actors remain in prior cell
|
||||
|
||||
## Notes
|
||||
|
||||
Remote actor spawning is intentionally not part of the current prototype. The
|
||||
receive loop stores plain remote-player state, and the game-thread proxy actor
|
||||
controller consumes a copied snapshot to move the one placed test proxy actor.
|
||||
Remote actors are dynamically spawned at runtime in the local player's current
|
||||
cell. The game-thread proxy actor controller consumes a copied remote-player
|
||||
snapshot to spawn, move, and hold proxy actors per remote `playerId`.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+6
-2
@@ -53,6 +53,7 @@ namespace
|
||||
};
|
||||
|
||||
constexpr auto kTransformSendInterval = 100ms;
|
||||
constexpr auto kIdleTransformHeartbeatInterval = 2s;
|
||||
constexpr auto kTransformLogInterval = 1s;
|
||||
constexpr auto kTransformSendPositionThreshold = 3.0F;
|
||||
constexpr auto kTransformSendRotationThreshold = 0.02F;
|
||||
@@ -524,13 +525,16 @@ namespace
|
||||
const auto isSpecialMovement = movementType != std::string_view{ "normal" };
|
||||
const auto hasMeaningfulTransformDelta = HasMeaningfulTransformDelta(lastSentTransform, currentTransform);
|
||||
const auto hasMovementStateChanged = HasMovementStateChanged(lastSentMovementState, networkMovementState);
|
||||
if (!isSpecialMovement && !hasMeaningfulTransformDelta && !hasMovementStateChanged) {
|
||||
const auto idleHeartbeatDue = (currentTime - lastSendTime) >= kIdleTransformHeartbeatInterval;
|
||||
if (!isSpecialMovement && !hasMeaningfulTransformDelta && !hasMovementStateChanged && !idleHeartbeatDue) {
|
||||
lastDebugSampleTransform = currentTransform;
|
||||
lastDebugSampleTime = currentTime;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSpecialMovement && currentTime - lastSendTime < kTransformSendInterval) {
|
||||
if (!isSpecialMovement && !hasMeaningfulTransformDelta && !hasMovementStateChanged) {
|
||||
// Idle heartbeat: keep remote clients updated even when both players are standing still.
|
||||
} else if (!isSpecialMovement && currentTime - lastSendTime < kTransformSendInterval) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user