# Responsive player movement To compensate for latency, *netfox* implements [Client-side prediction and Server reconciliation]. This documentation also refers to it as rollback. One use case is player movement - with CSP we don't need to wait for the server's response before the player's avatar can be updated. ## Gathering input For CSP, input is separated from player state. In practice, this means that there's a separate node with its own script that manages input. The job of this script is to manage properties related to input - for example, which direction the player wants to move: ```gdscript extends Node class_name PlayerInput var movement = Vector3.ZERO ``` These *input properties* must be updated based on player input. Hook into the [network tick loop]'s *before_tick_loop* signal to update input properties: ```gdscript func _ready(): NetworkTime.before_tick_loop.connect(_gather) func _gather(): if not is_multiplayer_authority(): return movement = Vector3( Input.get_axis("move_west", "move_east"), Input.get_action_strength("move_jump"), Input.get_axis("move_north", "move_south") ) ``` It is important to only update input properties if we have authority over the node. Otherwise we would try to change some other player's input with our own actions. ### Using BaseNetInput The same can be accomplished with [BaseNetInput], with slightly less code: ```gdscript extends BaseNetInput class_name PlayerInput var movement: Vector3 = Vector3.ZERO func _gather(): movement = Vector3( Input.get_axis("move_west", "move_east"), Input.get_action_strength("move_jump"), Input.get_axis("move_north", "move_south") ) ``` ## Applying movement The other part of the equation is *state*. Use the same approach as you would with your character controller, with the game logic being implemented in `_rollback_tick` instead of `_process` or `_physics_process`: ```gdscript extends CharacterBody3D @export var speed = 4.0 @export var input: PlayerInput func _rollback_tick(delta, tick, is_fresh): velocity = input.movement.normalized() * speed velocity *= NetworkTime.physics_factor move_and_slide() velocity /= NetworkTime.physics_factor ``` Note the usage of `physics_factor` - this is explained in [the caveats]. ## Configuring rollback Create a reusable player scene with the following layout: ![Node layout](../assets/tutorial-nodes.png) The root is a *CharacterBody3D* with the player controller script attached. The *Input* child manages player input and has the player input script attached. The [RollbackSynchronizer] node manages the rollback logic, making the player motion responsive while also keeping it [server-authoritative]. Configure the *RollbackSynchronizer* with the following input- and state properties: ![RollbackSynchronizer settings](../assets/tutorial-rollback-settings.png) ## Ownership Make sure that all of the player nodes are owned by the server. The exception is the *Input* node, which must be owned by the player who the avatar belongs to. After setting ownerships, **make sure** to call `process_settings` on *RollbackSynchronizer*. This call is necessary after every ownership change. *RollbackSynchronizer* sorts properties based on ownership, but this sorting is only done in `process_settings`. For example: ```gdscript @onready var rollback_synchronizer = $RollbackSynchronizer var peer_id = 0 func _ready(): # Wait a frame so peer_id is set await get_tree().process_frame # Set owner set_multiplayer_authority(1) input.set_multiplayer_authority(peer_id) rollback_synchronizer.process_settings() ``` Note that `peer_id` needs to be set from the outside during spawn. ## Smooth motion Currently, state is only updated on network ticks. If the tickrate is less than the FPS the game is running on, motion may get choppy. Add a [TickInterpolator] node and configure it with the same *state properties* as the *RollbackSynchronizer*: ![TickInterpolator settings](../assets/tutorial-tick-interpolator-settings.png) This will ensure smooth motion, regardless of FPS and tickrate. [Client-side prediction and Server reconciliation]: https://www.gabrielgambetta.com/client-side-prediction-server-reconciliation.html [BaseNetInput]: ../../netfox.extras/guides/base-net-input.md [network tick loop]: ../guides/network-time.md#network-tick-loop [RollbackSynchronizer]: ../nodes/rollback-synchronizer.md [server-authoritative]: ../concepts/authoritative-servers.md [the caveats]: ./rollback-caveats.md#characterbody-velocity [TickInterpolator]: ../nodes/tick-interpolator.md