Add proxy puppet hook and graph speed sync
Introduce a puppet vtable hook to preserve networked locomotion Speed and fix proxy cadence. Added F4TProxyPuppet (header + impl) which installs an Actor::Update hook that writes the desired graph Speed and calls UpdateNoAI for proxy actors so the engine does not recompute/zero Speed from controller velocity. Publish active proxy FormIDs and per-proxy desired speeds so the hook targets only proxy actors. Wire animationGraphSpeed through networking: parse/send a new "animationGraphSpeed" field and store it on RemotePlayerState. Proxy animation sync now prefers the authoritative animationGraphSpeed when present, otherwise maps movementSpeed ~1:1 to graph Speed (with sprint floor and clamping). Added graph variables speedSampled/speedDamped alongside Speed and updated snapshot population and diagnostics. Removed character-controller velocity injection (was causing physics/animation conflicts) and adjusted proxy movement logic to rely on graph variables plus kinematic SetPosition. Also: Publish puppet diagnostics from the controller, add sender-side local graph speed read diagnostic, update fake_player to compute and send animationGraphSpeed, and append detailed dev-log entries describing the root cause, diagnostics, and fixes. Build and runtime diagnostics added to verify hook behavior and cadence changes.
This commit is contained in:
@@ -48,6 +48,22 @@ ClientSnapshotProvider = Callable[[], list[dict[str, Any]]]
|
||||
WalkTargetProvider = Callable[[int], dict[str, Any] | None]
|
||||
|
||||
|
||||
def map_movement_speed_to_graph_speed(movement_speed: float, *, is_sprinting: bool = False) -> float:
|
||||
"""Match plugin MapMovementSpeedToGraphSpeed.
|
||||
|
||||
FO4 graph "Speed" shares the same world-units/sec scale as movementSpeed, so the
|
||||
mapping is ~1:1 (clamped). Confirmed from local-player graph debug: run movementSpeed
|
||||
~306 lines up with graph Speed ~296-373.
|
||||
"""
|
||||
if movement_speed < 1.0:
|
||||
return 0.0
|
||||
|
||||
graph_speed = movement_speed
|
||||
if is_sprinting:
|
||||
graph_speed = max(graph_speed, 350.0)
|
||||
return min(graph_speed, 500.0)
|
||||
|
||||
|
||||
class FakePlayerClient:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -537,6 +553,11 @@ class FakePlayerClient:
|
||||
"weaponDrawn": False,
|
||||
"movementSpeed": movement_speed,
|
||||
}
|
||||
if is_moving and movement_speed >= 1.0:
|
||||
packet["animationGraphSpeed"] = round(
|
||||
map_movement_speed_to_graph_speed(movement_speed),
|
||||
1,
|
||||
)
|
||||
encoded = json.dumps(packet, separators=(",", ":")).encode("utf-8") + b"\n"
|
||||
with self._send_lock:
|
||||
connection.sendall(encoded)
|
||||
|
||||
Reference in New Issue
Block a user