I'm currently developing a 3D multiplayer game using Godot 4.2 and have hit a bit of a snag regarding implementing server-authoritative movement, despite having made some progress. Here's a breakdown of what I've achieved and the challenges I'm facing:
What I've Done:
I've been using PlayerBody3D for move and slide functionality to handle player movement.
I've implemented client-side prediction to some extent, allowing players to move smoothly on their end.
My Understanding So Far:
To transition to server authority, I believe the next steps involve sending player inputs (alongside a timestamp or input order) to the server, which also stores them locally.
The server then processes these inputs. However, it's unclear to me whether this processing involves simulating the movement on the server or using a method like move and slide on server-side objects.
Where I'm Stuck:
Handling the server response: When the server sends back the confirmed state, there's often a noticeable lag, leading to unhandled input. If a player's position is adjusted to match the server's, how can I properly simulate movement (like move and slide) over time to correct any discrepancies?
Currently, my workaround involves players sending their positions to the server, which then broadcasts these positions to ensure synchronization. However, this method leaves room for cheating, as players could manipulate their client code to alter movement speeds or gravity.
Questions for the Community:
How can I effectively simulate or process player movement on the server side to maintain server authority, especially regarding using move and slide or an equivalent method?
What strategies can I employ to manage and correct for the delay in server responses, ensuring that player movement remains smooth and accurate according to the server's state?
Are there recommended practices within the Godot community for securing player movement against cheating, specifically when trying to shift from a client-authoritative to a server-authoritative model?
func handle_movement(_delta):
if !is_on_floor():
velocity.y -= gravity * _delta
if Input.is_action_just_pressed("move_jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_backward")
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized().rotated(Vector3.UP, $MeshContainer.rotation.y)
if direction:
pathing = false
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
if !Input.is_mouse_button_pressed(MOUSE_BUTTON_RIGHT) and !Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) and input_dir != Vector2.ZERO:
reset_camera()