float precision problem when calculating on different unity instances?

I’m currently working on a weapon (projectile) system for a multiplayer game.

The following snippet is used (both on client and server) for calculating the origin and direction of the firing player based on the camera position (= where the crosshair points to):

Vector3 origin = this.transform.TransformPoint(cameraPivot);
Vector3  direction = Quaternion.AngleAxis(cameraRotationX, this.transform.right) * this.transform.forward;

Unfortunately I’m receiving different results on the client and server instance:

Client:

origin: (139.4957, 1.6800, -63.1644)
direction: (0.3591, -0.2588, -0.8967)

Server:

origin: (139.4919, 1.6800, -63.1545)
direction: (0.3430, -0.2619, -0.9021)

Could this be a float precision issue?

Is it an issue though? If your projectile fires do you see any difference? Remember, a large part of game development is fake it till you make it!

Probably precision issues. I so hate Unity’s love of singles for coordinates.

Have you also observed data for the inputs into the operations, such as all the details in this.transform, cameraPivot, and cameraRotationX? First make sure that the inputs are identical. If they’re not, then at least some of the divergence must be upstream, earlier in the process.

If the inputs are identical, then you’re likely just getting hit by the fact that different platforms frequently optimize math in different ways, especially through approximations of trigonometry functions, square roots, and so forth, which might be utilized under the hood by the functions you’re calling. Cross-platform floating point math is hard, nearly to the point of being impossible. You could switch to fixed point math, but that’s a huge implementation cost, especially in an engine like Unity that is absolutely not designed to be flexible with the numeric types used for core operations.

If you’re doing calculations both on the client and server, you’ll probably just have to accept that sometimes they’ll disagree, and therefore you should work out a consistent method for resolving the disagreement. In the short term, I’d recommend whatever is easiest to implement (probably either server-always-right or relevant-client-always-right). For example, I believe a lot of FPS games trust (with care) the client of the player doing the shooting: If it looked like a hit on the player’s screen, then count it as a hit, even if the server thinks it was a near miss.

The “with care” caveat is due to the easiest implementation not being enough, because it allows easy cheating. So the method for resolving the server/client disagreement gets messier, where the client is trusted, but only if it doesn’t deviate too far from the server. This is the sort of thing you do after you have things mostly working and feeling good, but you know that there are edge cases that need to be dealt with before you can declare the game finished.

It’s no real issue, as the hit point is almost the same (if we take lag into account it won’t matter anyway), but I was just wondering if there is a issue with my code or if it’s related to float precision.

Thanks for the detailed answer. The inputs are the same, I’ve double checked that already before and after the calculation posted above, only the calculated results differ by approx. 0.01f.

As my setup is fully authoritative I’ll not implement any workaround.