Proper way to keep networked physics states in-sync?

Post Reply
co2
Posts: 9
Joined: Mon Mar 14, 2016 3:46 pm

Proper way to keep networked physics states in-sync?

Post by co2 »

Hello!

I am implementing an MMO game that uses Bullet Physics and I am having issues keeping the networked physics states in-sync.

The server simulates things server-side, and the client simulates things client-side. When the server-side state changes (such as a character moving a rock represented as a rigid body) the changes are sent to all the clients which incorporate them into their states and then continue the simulation on their own from there. The clients basically run the simulation and wait for updates from the server to verify that their simulation is correct, and if they differ they update to what the server has provided.

The problem that I am having is that everything stays in sync until a collision happens (such as two boxes colliding). I've verified that up until that point the physics states are identical, but after the contact is made the collision object array (acquired from btDiscreteDynamicsWorld::getCollisionObjectArray) is different, and after that cycle the linear and angular velocities can differ, as well as world transformations etc.

I've been looking everywhere for some answers to this question (forums, wiki etc). I'm quite desperate at this point. I was hoping that maybe someone has dealt with a similar issue before and/or there is some documentation somewhere that specifies the proper way to synchronize bullet physics states across the network.

I update my game-state at fixed time-steps and all the changes that happen on the server are incorporated on the same cycles and in the same order on the client(s) as they were applied on the server. I apply changes to rigid bodies like so:

Code: Select all

rigidBody->setWorldTransform(t);
motionState->setWorldTransform(t);
rigidBody->setInterpolationWorldTransform(t);
rigidBody->activate();
rigidBody->clearForces();
rigidBody->setLinearVelocity(btVector3(info.linearVelocity[0], info.linearVelocity[1], info.linearVelocity[2]));
rigidBody->setAngularVelocity(btVector3(info.angularVelocity[0], info.angularVelocity[1], info.angularVelocity[2]));
rigidBody->setInterpolationLinearVelocity(btVector3(info.linearVelocity[0], info.linearVelocity[1], info.linearVelocity[2]));
rigidBody->setInterpolationAngularVelocity(btVector3(info.angularVelocity[0], info.angularVelocity[1], info.angularVelocity[2]));
The world transform is acquired by calling btRigidBody::getWorldTransform() and the same for the linear/angular velocities. After these changes are applied, the physics state will be identical, unless a contact was generated this cycle.

Is there anything that I can do to make the Bullet Physics states identical?
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Proper way to keep networked physics states in-sync?

Post by drleviathan »

Can you make the Bullet simulation exactly the same server and client?

The short answer: no, not for server-client situation where the clients may be running entirely different hardware than the server.

The long answer: you should read these articles: http://gafferongames.com/networked-phys ... d-physics/
co2
Posts: 9
Joined: Mon Mar 14, 2016 3:46 pm

Re: Proper way to keep networked physics states in-sync?

Post by co2 »

drleviathan wrote:Can you make the Bullet simulation exactly the same server and client?

The short answer: no, not for server-client situation where the clients may be running entirely different hardware than the server.

The long answer: you should read these articles: http://gafferongames.com/networked-phys ... d-physics/
Thanks! I've already implemented those methods, and the server/client are being run on the same computer. The physics state should be identical given those conditions but it isn't. Changes are sent from my server to the client and incorporated on the same time-step and in the same order, and once the changes are applied the two states will be identical until a contact is generated, at which point in time the two states diverge, radically.

E.g., bullet physics is somehow generating differing contacts despite identical simulations on the same machine.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Proper way to keep networked physics states in-sync?

Post by drleviathan »

I looked through the code and found some randomization happening in the constraint solver classes, however, as far as I can tell relevant behavior flags are not set by default, so the randomization feature should be bypassed. The constraint solvers are used (I think) to solve the contact points so maybe you could try to make sure you are not falling into that randomization code.
co2
Posts: 9
Joined: Mon Mar 14, 2016 3:46 pm

Re: Proper way to keep networked physics states in-sync?

Post by co2 »

drleviathan wrote:I looked through the code and found some randomization happening in the constraint solver classes, however, as far as I can tell relevant behavior flags are not set by default, so the randomization feature should be bypassed. The constraint solvers are used (I think) to solve the contact points so maybe you could try to make sure you are not falling into that randomization code.
Thanks! Are you referring to the btSequentialConstraintSolver class? I found that as well, and synchronizing the random state from it didn't help.

I was able to get things to sync up by completely resetting bullet physics every cycle on both the server and all the clients. I made a list of all the collision objects, deleted the dynamics world, constraint solver etc and re-allocated them, then added all the objects back in. Prior to now I wasn't entirely sure the problem was with bullet physics but at this point I am highly confident it is. There is something in there that causes things not to stay in sync.

If someone is considering using bullet physics for a game with networked physics I'd recommend against it. If you are already committed / find yourself in a similar situation I'd highly recommend staying away from any of the built-in serialization code, and be sure to use btRigidBody::getWorldTransform() rather than what's passed to the motion states. Fix your timestep and make sure everything happens on the same cycle and in the same order across all the simulations, and reset bullet physics every cycle.
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Proper way to keep networked physics states in-sync?

Post by drleviathan »

If someone is considering using bullet physics for a game with networked physics I'd recommend against it.
I think that statement needs qualification. Bullet might not be suitable for the Deterministic Lockstep method for networked physics, but that is only one of three that Glenn Fiedler discusses in his series on networked physics. The other two are: Snapshots and Interpolation and State Synchronization.
co2
Posts: 9
Joined: Mon Mar 14, 2016 3:46 pm

Re: Proper way to keep networked physics states in-sync?

Post by co2 »

drleviathan wrote:
If someone is considering using bullet physics for a game with networked physics I'd recommend against it.
I think that statement needs qualification. Bullet might not be suitable for the Deterministic Lockstep method for networked physics, but that is only one of three that Glenn Fiedler discusses in his series on networked physics. The other two are: Snapshots and Interpolation and State Synchronization.
There are several reasons I wouldn't recommend bullet for a multiplayer game at this point:

1. Two Bullet Physics states initialized in the same exact way with every change applied to them in the same way (in the same order and on the same fixed time-steps), will still diverge. That shouldn't happen.

2. The documentation is poor, and portions of the code are extremely misleading. I lost a bunch of time just to figure out that motion states aren't passed their actual positions with setWorldTransform, even though getWorldTransform requires the actual position, for example.

3. The functionality to save/load the physics state isn't well implemented or even functional. I should be able to call a single function that populates a buffer with a snapshot of the physics state (either a portion or the whole thing). I should then be able to load that in a separate / reset physics state by calling a single function and continue the simulation exactly as it would have in the original simulation from the point of that snapshot.

I was really impressed up to this point. These are some serious shortcomings and people should know about them before they get caught in the awkward position I find myself in.
hyyou
Posts: 96
Joined: Wed Mar 16, 2016 10:11 am

Re: Proper way to keep networked physics states in-sync?

Post by hyyou »

Is it possible to sync only game logic?

Let the server rule all the game logic, and let clients use physic engine only for cosmetic.

Even if Bullet can sync the physic engine, sync-ing the whole state of Bullet between 2 computers is too harsh. (more data-flow)

I have not found any real-time games that can sync physic of 2 computers. They can only fake it, I guess.
co2
Posts: 9
Joined: Mon Mar 14, 2016 3:46 pm

Re: Proper way to keep networked physics states in-sync?

Post by co2 »

hyyou wrote:Is it possible to sync only game logic?

Let the server rule all the game logic, and let clients use physic engine only for cosmetic.

Even if Bullet can sync the physic engine, sync-ing the whole state of Bullet between 2 computers is too harsh. (more data-flow)

I have not found any real-time games that can sync physic of 2 computers. They can only fake it, I guess.
Yeah, the way many games solve the problem is to avoid having to sync the physics in the first place. The problem arises when the physics is integral to the game logic. Suppose a racing game like Mario Kart, for example. As to whether or not it is possible, I've successfully implemented two multiplayer game engines that utilize physics, both different kinds of games that utilize the physics in different ways. So it definitely is possible.

It would be a lot easier if implemented properly in Bullet Physics and if some proper documentation were added, and the code was cleaned up a bit (rename ambiguous classes like "btMotionState" to "btGraphicsState" or something similar).
co2
Posts: 9
Joined: Mon Mar 14, 2016 3:46 pm

Re: Proper way to keep networked physics states in-sync?

Post by co2 »

drleviathan wrote:
If someone is considering using bullet physics for a game with networked physics I'd recommend against it.
I think that statement needs qualification. Bullet might not be suitable for the Deterministic Lockstep method for networked physics, but that is only one of three that Glenn Fiedler discusses in his series on networked physics. The other two are: Snapshots and Interpolation and State Synchronization.
Both the solutions he proposes are only functional when updates can be sent faster than divergences happen. His example uses 25kbps of bandwidth for a very simple simulation with some blocks. 25kbps for such a simple simulation isn't practical for many applications. Build a more complex simulation or have more clients that need synchronization and you can easily exceed bandwidth limits, at which point in time you will have massive discontinuity issues in each separate simulation.

For the application that I am working on I can only send updates once every second or two. Even if I send updates faster (say 5 times a second) there is still noticeable lag, even with smoothing. I found a workaround though, but it requires completely resetting bullet physics each cycle on both the server-side and client-side which is not pretty and certainly not efficient.
Post Reply