In general, the server should be the sole authority for calculating object positions and movement vectors. The clients should only send their intention to move to a certain destination or into a certain direction, and the server should respond with a new movement vector, when it decides to allow the client to do so.
The server should also be allowed to send movement vectors which are not a response to a client, or even directly contradict what the client is saying, like when the movement destination of the client is blocked by another object.
A client can assume that the server will allow them to perform a move and already show the player character moving even though the server didn't sent a new movement vector. This makes the network latency less apparent to the user and thus offers a more fluent game experience. But the client should be prepared to correct the position of the player character when the server decides to deny or interrupt the movement, for example because there is a collision with another object.
Example:
- User issues a move command
- Client checks if the move may be performed according to its current view of the game state, and decides that it's possible
- Client sends the move command to the server, and already starts to move the player character, because it assumes that the server will allow it.
- Server receives the move command, and decides to deny it because there is something in the way the client wasn't aware of or didn't consider to be in the way due to timing differences
- Server sends a rejection message to the client
- Client stops moving the player character and moves it back to the original position