Game Development Community

Physics and Server/Client

by Ryan Mounts · in Technical Issues · 09/22/2008 (9:18 pm) · 8 replies

My question is regarding physics related code. Specifically, I've implemented Gary Briggs' odescript resource, but it seems that the ode objects' motion is not rendered smoothly. When client-side interpolation is disabled, the motion is a little choppy (because it's only being updated every 32 ms despite the framerate), but it "feels" physically correct. When client-side interpolation is enabled, a very unnatural jerkiness appears. So I've been digging through other physics code, like in rigidshape.cc and item.cc, for example, to see how other physics objects are implemented.

So here's my problem... please keep in mind that this is my first real dealings with tickable objects. :) I'm having trouble wrapping my head around what's going on in the server/client interactions for the stock physics objects. For example, I don't quite understand the details behind warpTicks and backstepping. Is the physics simulation taking place solely on the server side and the client simply one tick behind and linearly interpolating between two known object transforms? Or is the client using current state info (linear and angular position/velocity) to predict a future transform until it gets the next "real" transform from the server. It seems like the former to me. Why does interpolateTick() update the renderObjToWorld matrix while processTick() updates the ObjToWorld matrix? These are just a few of the things I'm trying to figure out. Odescript does not use the mDelta structure or interpolate like the normal Torque physics objects, so I'm assuming this is where the jerkiness is coming from. I know this is a very broad (and kinda vague) question, but thanks for any helpful info!

#1
09/23/2008 (5:31 pm)
Well, nevermind... I've pretty much got it all figured out now. Looks like I just needed to sleep on it. :)
#2
09/25/2008 (9:06 pm)
I changed how the ode server objects interact with the client objects and how things get interpolated on the client side, and the simulation looks correct now, a.k.a everything renders smoothly. There's a problem getting the client side prediction working, though; it's disabled by default in odescript, and the comments in the scripts reveal that it was disabled because it was broken from the start.

I've found that the problem is related to a dependence of certain objects upon the existence of other objects in order to be ghosted correctly on the client. For example, before an ode rigid object can be properly ghosted, there has to be an ode world ghost and an ode mass ghost. And only then can the ode shape be properly ghosted. I don't really like these dependencies, and maybe the right path would be to eliminate them altogether, but that would take a good deal of work. So I'm looking for a way to guarantee that server objects get ghosted in a certain order. Anybody have any ideas?
#3
09/26/2008 (9:06 am)
Yeah ghosting order dependencies are a pain. We had some of the same issues integrating physx. I don't know of a way to enforce an order, although I think it generally transmits the objects in your mission file in the order they are created in the file. You probably don't need to ghost the world object, just create it as a global on startup. If your shape object requires a mass object then maybe those should be combined and ghosted at one time. Eg, pack the mass properties and allocate it with those properties in unpack or onAdd.
#4
09/26/2008 (10:03 am)
@James, actually, they're transmitted in reverse order from what I recall when Tom and I were trying to figure out the issues with the PhysXWorld vs. the ragdoll creation. I could be wrong, but I'm pretty sure that's the case.

I also recommend, as James says, not even bothering using the ghosting system for your main "world" physics sim object. It creates all sort of annoying creation dependencies. It's much easier to simply give it a create/start function and a destroy/end function and call those at the right times from script.
#5
09/26/2008 (10:14 am)
Quote:There's a problem getting the client side prediction working, though; it's disabled by default in odescript, and the comments in the scripts reveal that it was disabled because it was broken from the start.

Well. I never really fully got a clientside physics simulation running properly, IIRC, everything was just linearly interpolated [like everything else in torque, actually]. There is real prediction in the sense of a full clientside simulation, but it runs into problems. I don't remember how to enable it, but I do remember finding that by disabling network updates of the objects you could see real client-side stuff working.

If you're doing a single player game, then you can up the network rate and network packet size, and you'll find that the whole thing runs a lot more smoothly.

Quote: I don't really like these dependencies, and maybe the right path would be to eliminate them altogether

Yes. That is, indeed, the right path. See, my original design was basically to wrap ODE and provide it to torquescript, exactly as-is. Hence, "ODEScript". At that point, I didn't really know much about torque networking, so it wasn't until I'd sorted out all the objects and consolemethods that I started to find myself having issues with the networking. ODEScript originally ran in Torque2D, and was added to TGE and TSE much later, so networking was pretty moot in the early stages anyway.

As you clearly noticed, this leads to various bits of messy code where the mass has to check to see if its respective body is already on the client, and the body has to do the opposite, so they can meet up correctly. This is just kinda sucky. The world, I did experiment with creating it on client and server and not ghosting it, and I believe the code understands this if you just set global variables appropriately.

One thing that the engineer in me wanted to be able to do was to potentially have multiple worlds, something that a token global variable wouldn't allow. As per usual, it's not something that's practically very useful, but I liked the idea. But it did mean that worlds needed to be ghosted.

You can't guarantee ghosting order. Give up on that one :-/

A much better approach in retrospect would have been to make things like the mass part of the body itself in torque. Nothing out of the question, actually, you could combine the two without too much hassle. That wouldn't fix a lot of your other problems, but it'd help with a lot of the really messy code that sets up objects as they cross the network.

A much bigger problem than just masses & bodies is joints & bodies. You need the two bodies before you can set up the joint, and that cannot easily be done. One thing I was thinking about for both setup and for network updates were considering groups of bodies joined by joints as an "island", and always updating the entire island in one shot. That would simultaneously fix the problem where one body in a chain gets a network update that movies it a long way, and the rest of the chain looks awful while it tries to compensate for that.

And all my big dreams of this were pretty much nixed when I quit using torque and started writing my own game from lower-level, more-crossplatform components.

Gary (-;
#6
09/26/2008 (10:19 am)
Thanks for the reply, James. Yeah, I set out to get the odescript resource working properly to serve as a starting point for integrating Havok. I actually just figured out how ode joints are dealing with these ghosting dependencies in odescript, because the ghost needs the rigid body ghosts to exist before the joint ghost can be added to the client world. So I'm going to try to move the same logic over to the ode mass, rigid body, and shape, so that they wait for each other to all get to the client before being added to the client simulation.

I agree that the client world really does not need to be a ghost of the server world, since there's no reason for them to know about each other. If this does not work, then I'll probably try to combine objects like you suggested. That's where I was already beginning to lean, because I think it would reduce network traffic compared to how it's implemented now. Thanks for the sanity check!
#7
09/26/2008 (10:42 am)
Wow, I run off in the middle or replying in order to do some "real" work , and I get all kinds of replies. :) This is really helping me understand things having other people chime in with their thoughts. Yeah, Gary, I'm trying to get things working without ripping out any of your code, but rather making small changes that leave me with working physics after each step. So that's why I haven't started combining anything yet. I was considering lumping the body and mass into odeshape, but then I realized that the joints depended upon the bodies too, so that ended up requiring a much bigger change than I'm prepared to make at the moment. I was still planning to incorporate the mass, though, because that seemed easy. Yes, I believe you have the code to allow for creating the client world manually... I was confused by some of your implementation decisions, but now that you mentioned that, some more things are making more sense! :)

What I did on the interpolation side of things is I took the code from rigidshape.cc and modified it to work with odescript. So now it interpolates the same way as vehicles, items, etc. Right now I have NO client side prediction implemented at all, and it renders very smoothly based solely upon the server updates with default rate and packet size.

Thanks for the replies everyone. I feel like I'm getting somewhere slowly but surely!
#8
09/26/2008 (10:44 am)
You probably need a way to serialize your ODE objects. Not that I know anything about ODE, but in PhysX you can create a bunch of actors with shapes, linked together with tons of joints using a max plugin, then serialize that into xml.

Then you can load that same xml on the server / client, so the torque-ghosting is straighforward, send the xml filename in pack/unpack and load it in onAdd. Of course doing network-updates between server client for this object is a whole other problem.

It might be worth looking at exactly what you features you need, and just get that working, since somethings wouldn't require a big framework to be setup in advance.