Character movement component does the same thing roughly. That’s what client-side prediction is. You input movement and “your” client executes it immediately. The inputs and results are buffered in a SaveMove. On next ClientDeltaSendMove all new moves are packed and sent to the server. Server attempts the same moves then compares its result against the clients result. If they differ, the server sends that client a correction, otherwise an ACK for the move.
There’s always desynchronization in multiplayer. The latency of the players, hardware/software differences, floating point precision errors etc. You’ll never sync anything 100%. Best you can hope for is a solid approximation.
You should be doing your own checks and balances in this regard.
For single and first burst/auto shot I’m sending the clients data (what it used for the shot) to the server.
Server calculates its own values and compares against the clients. If it’s close enough to the servers results then the server will use client data, otherwise server uses its values. There’s favor the shooter here but I’m talking small data offsets as limits. 125.012 vs 125.053 (1/8 cm against 1/2 cm)
In the clients firing functions (Single, Burst, Auto) I’m calling a Projectile Trajectory function.
The server has its own version of this function that handles the scrutinization and some anti-cheat.
Client might see a clean hit, but the server says no. This is common across all shooters. On sims we aren’t spawning the projectile at the sims muzzle. We are spawning it where ever the servers muzzle was at the time it fired.