Unity UNet - the problem of determinism

Started by
6 comments, last by hplus0603 7 years, 4 months ago

Hello, I am new to network stuff but I have a project in mind and I have become concerned about the problem of desynchronization, due to the difficulty in predicting the results of floating point calculations from client to client. I will be using a client-server architecture , client-side prediction and entity interpolation and server reconciliation. My main concerns are related to making deterministic calculations on each client when the results of floating points can't be guaranteed.

I am aware of packages like Decimal but those seem too slow to solve the concerns.

Perhaps my worries are misguided, I would greatly appreciate if someone in the know could help me understand which features of unity I should ignore, how I should go about solving the problem and if it is even as much of an issue as I worry, perhaps for small, fast-paced matches as I envision for my game it won't be such a major issue if there is a tiny discrepancy. I appreciate that it would be more likely to grow into a much more problematic situation were it a p2p real time strategy or something, as there would be potentially hundreds of actions and tiny discrepancies could accumulate.

Am I overthinking this? If not what should I do? My project will mainly target smart-phones and tablets, but also desktop and potentially webgl 2, I would prefer to sort players by input type rather than platform. I can't have easily-deterministic floating point so the results will vary. Would I have to implement my own physics and collisions in fixed point? Does unity offer a solution to this that I am just not aware of ?

I don't want to have to have players snapping back all the time because the server decides the predicted state is incorrect, it would be quite troublesome.

Advertisement
Floating point math can be made fully deterministic as long as all clients and servers are running the same code compiled by the same compiler version.

However, Unity is not built to provide determinism. The physics engine it's built on top of is not deterministic. Thus, if you want determinism, you have to build the entire game state simulation loop yourself (this includes collision detection etc.)

Most Unity games deal with the fact that objects are slightly out of sync, and just let the server make the "important" decisions.
enum Bool { True, False, FileNotFound };

Floating point math can be made fully deterministic as long as all clients and servers are running the same code compiled by the same compiler version.

Yes, I know this but from the very start I'm targeting multiple architectures so I can't have predictable results. Actually that's something I'm not certain of, since c# compiles to bytecode is it even possible to consistently get the deterministic results on the same machine across builds?

However, Unity is not built to provide determinism. The physics engine it's built on top of is not deterministic. Thus, if you want determinism, you have to build the entire game state simulation loop yourself (this includes collision detection etc.)

I thought that might be the case, which is a bit troublesome. Can you suggest some reading and some code samples that might help me learn how to write deterministic network code? I already have a few resources open but so far they haven't been enough help that I have wrapped my head around the whole issue.

Most Unity games deal with the fact that objects are slightly out of sync, and just let the server make the "important" decisions.

I don't know how to deal with it though, that's the main problem I think. I will use an authoritative server but I don't want to have to transmit the complete state for everything, but if I use client side prediction as I plan then when the server sends back saying I'm not where I should be the player will be snapped back. Unless I perhaps allowed an error margin that would prevent such minuscule desync issues... but then over time my characters state on my prediction will be sufficiently different that a snap back would occur anyway, so all I've achieved is a reduction in the snapping?

If I didn't force the players prediction to adjust to the server simulation then the game would become unplayable for everyone... and if I don't do client-side prediction/ entity interpolation then it will be even worse...

since c# compiles to bytecode is it even possible to consistently get the deterministic results on the same machine across builds?


C# also supports generated-code targets these days (similar to ngen but not at install time? Something like that.)

However, you're probably better off just building all your simulation using integer / fixed point code.

The classic article series on deterministic networking is the "1,500 archers on a 28,800 modem" from gamasutra, describing Age of Empires.

What is your game? Is deterministic simulation really 100% necessary for you? Can you live with the necessary round-trip time of command latency?
enum Bool { True, False, FileNotFound };

since c# compiles to bytecode is it even possible to consistently get the deterministic results on the same machine across builds?

C# also supports generated-code targets these days (similar to ngen but not at install time? Something like that.)

I'll have to read up on this, it seems interesting.

However, you're probably better off just building all your simulation using integer / fixed point code.

I'm not very familiar with fixed point code, especially optimised fixed point for a fast-paced multiplayer... But I have managed to source an awful lot of content to read so I'm sure I'll pick something up...

The classic article series on deterministic networking is the "1,500 archers on a 28,800 modem" from gamasutra, describing Age of Empires.

I remember stumbling onto this a long time ago, I never really read it but perhaps I should.

What is your game? Is deterministic simulation really 100% necessary for you? Can you live with the necessary round-trip time of command latency?

My game is sort of a tame bullet hell, the physics and collision could probably be pretty simple. Some gravity, some displacement forces, it's 2d so could possibly even get away with simple aabb for collision on the players and quadtree for the bullets. The main issue here is my lack of familiarity with network programming. Since it's primarily targeting smart devices I wouldn't want to use up too much expensive mobile data. The game will probably be hosted on either Amazon Web Services or Microsoft Azure. Preferably I would be able to just send batched inputs , use prediction for the players own character, interpolate between most recent positions for all else and still remain consistent with the approved server state. I'm not sure I would want to go the only solution I so far understand, which would be to make the players authoritative over their own positions... I'm not keen on that idea but if I did that and did some sanity checks server side, then it wouldn't matter that the clients own model might calculate differently than the server, as it would be approved by the server and everyone else would just interpolate between the two points the server said were believable.

It does seem to make it far easier to cheat, though... and I'm extremely ignorant about this topic so I could be missing a much neater solution. In fact, that might not even be a solution at all for all I know, which is troublesome.

It's late where I am so I'm going off for now, thanks for your help so far and I'll check back tomorrow to see if anyone else has some suggestions or if you yourself have responded.

Much appreciated and goodnight :-)

The control latency of fully deterministic networking is unlikely to work well for a "bullet hell" type of game.
I think you will be better off doing "mostly deterministic" (float, and the built-in physics engine, is good enough for display purposes) where you show initial effects based on client simulation, and actual hits/kills based on server messages.
Now, if you can live with the control latency for the deterministic simulation/networking, then that solves the "I shot him but be thought he was safe behind the wall" problem, which is generally the hardest bit of non-deterministic simulation.
enum Bool { True, False, FileNotFound };

The control latency of fully deterministic networking is unlikely to work well for a "bullet hell" type of game.
I think you will be better off doing "mostly deterministic" (float, and the built-in physics engine, is good enough for display purposes) where you show initial effects based on client simulation, and actual hits/kills based on server messages.

That's actually what I had in mind, I would calculate the bullets server side and render them client side, the hitbox will give a bit of leeway for the player anyway and the differences will be minuscule anyway, I don't see it as being as big a problem as the player becoming desynced from the server and being snapped back due to reconciliation. I'm glad you've suggested this because I was especially worried about the possibility of having to work out bullets with fixed point, and from my understanding fixed point is typically more expensive.

Now, if you can live with the control latency for the deterministic simulation/networking, then that solves the "I shot him but be thought he was safe behind the wall" problem, which is generally the hardest bit of non-deterministic simulation.

I'm not sure if I could live with it or not because I'm not sure about how severe it would be. I imagine it will be really quite heavy so I probably would favour letting players render the bullets themselves and having the server be authoritative about it, it will be fast paced anyway so players probably won't notice minor issues and since I will adjust the hitboxes in their favour, all the more so.

There won't really be walls, though so even more reason to favour the cheaper solution. I would like to be able to collide bullets and for that, I think I'd probably use a quadtree. I reckon that would be "good enough" I would also like players to be able to use other players as "walls" so I suppose there are some objects that could be used for cover, but I don't think hiding behind a player but still getting shot would be as much of an experience breaking thing as being in a completely different room and getting done in!

My main issue is with applying displacement forces and if I do all that with floating point it could lead to some very different results across hardware and software architectures. If anything needs to be as close to exact as possible it would have to be the player's location, due to input and due to the effects of forces. But there will be only a handful of players compared to hundreds of bullets, so in that respect, I probably could suffer control latency.

Generally, the physics of the displacement and falling need to be consistent across platform or reconciliation will force clients to adjust their models to the servers, and due to being a fairly frequent operation, the experience would be unusable.

It would also be nice if I had the option of adding in a replay feature at a later date if there was demand for it. I think, again with that people won't be as frustrated if the bullet storms are fractions of a pixel off but if their avatar is on the wrong side of the world they will probably be frustrated. My main goal is to create a fun and engaging experience so I'm worried about this likelihood!

ps. I hope I'm understanding this right but by control latency you mean the latency that would be introduced as a result of the more computationally expensive fixed point/ deterministic calculations compared to the hardware optimised floating point?

Thanks for all your help so far, I feel like I'm getting closer to answering some of those frustrating questions that are floating around my mind!

Generally, the physics of the displacement and falling need to be consistent across platform or reconciliation will force clients to adjust their models to the servers, and due to being a fairly frequent operation, the experience would be unusable.


I think your assumption about the feeling of the corrections is unfounded.
99.99% of the time, the correction will be so small that the player won't feel it at all.
Especially if you make small animation tweaks to apply the correction over time.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement