extends Node @export var sync_rate: float = 0.05 # 20 Hz var _owner_id: int = 1 var _timer: float = 0.0 # Interpolation buffer for remote dolphins var _remote_pos: Vector3 = Vector3.ZERO var _remote_yaw: float = 0.0 var _remote_pitch: float = 0.0 var _has_remote_data: bool = false var _interp_speed: float = 12.0 func setup(owner_peer_id: int) -> void: _owner_id = owner_peer_id set_multiplayer_authority(owner_peer_id) func _process(delta: float) -> void: if NetworkManager.is_solo(): return var parent_node := get_parent() if not is_instance_valid(parent_node): return if multiplayer.get_unique_id() == _owner_id: # Send our transform at sync_rate _timer += delta if _timer >= sync_rate: _timer = 0.0 var pos: Vector3 = parent_node.global_position var yaw: float = parent_node.rotation.y var pitch: float = 0.0 if parent_node.has_node("CameraPivot"): pitch = parent_node.get_node("CameraPivot").rotation.x var boosting: bool = false if "is_boosting" in parent_node: boosting = parent_node.is_boosting receive_transform.rpc(pos, yaw, pitch, boosting) else: # Interpolate toward remote state if _has_remote_data: parent_node.global_position = parent_node.global_position.lerp( _remote_pos, _interp_speed * delta ) parent_node.rotation.y = lerp_angle(parent_node.rotation.y, _remote_yaw, _interp_speed * delta) if parent_node.has_node("CameraPivot"): var pivot: Node3D = parent_node.get_node("CameraPivot") pivot.rotation.x = lerp_angle(pivot.rotation.x, _remote_pitch, _interp_speed * delta) @rpc("any_peer", "unreliable") func receive_transform(pos: Vector3, rot_yaw: float, rot_pitch: float, boost: bool) -> void: _remote_pos = pos _remote_yaw = rot_yaw _remote_pitch = rot_pitch _has_remote_data = true var parent_node := get_parent() if is_instance_valid(parent_node) and "is_boosting" in parent_node: parent_node.is_boosting = boost