Page 1 of 1

Networking Physics

Posted: Sat Jan 19, 2013 8:32 pm
by _untitled_
Before I came to BEPU, I had my own little jerry rigged AABB collision system, since my terrain was composed of blocks.
This was pretty fast, and it made coding an authoritative server a breeze - I could store states, rewind, and replay specific entities at a time. The client would send a packet number along with the timestep (i.e. "16 milliseconds") used for the prediction calculations, and the server would process the individual player's physics with the timestep, and then send back a packet with the packet number and the authoritative position. This pretty much guaranteed that the client and server were always synced (or could "understand" each other with infinite precision) in terms of packet number.

I've read another thread on this forum that asked if processing a single entity is possible with BEPU, but it appears that it's extremely complicated and not feasible.

So how feasible is it to give each Player object on the server their own space? Memory wise, how much space would this take up? My terrain is composed of ~1,000,000 triangles, *3 that gives you 3,000,000 vertices. Since my game is a run-and-shoot-esque FPS, the only really collisions that would occur would be between the players and the terrain.

I've also read online that the physics engines should be run at a fixed timestep - that is to say, you have an accumulator that fits as many dt chunks as possible in the elapsed game time, and saving the remaining fractional dt for the next frame. I don't see how this could help though - wouldn't the lack of processing the fractional dt create occasional jumps in the game, and if a player's computer lagged, wouldn't everything blow up?

Thanks for any help!

Re: Networking Physics

Posted: Sat Jan 19, 2013 9:19 pm
by Norbo
I've read another thread on this forum that asked if processing a single entity is possible with BEPU, but it appears that it's extremely complicated and not feasible.
Pretty much correct- the engine is designed to run global simulations, after all. Tricking it into updating only parts of the simulation basically requires turning off parts of the simulation in one way or another. Depending on the goal, it isn't necessarily complex and can be quite feasible, but it is certainly not natural. The closer the desired simulation is to a full dynamic simulation, the worse this approach becomes.

For example, storing states, rewinding, and replaying is still very possible. It might not be computationally feasible if there's a few hundred dynamic objects that need to be resimulated every single time, but if its just a couple of dozen characters, it's pretty cheap.
So how feasible is it to give each Player object on the server their own space? Memory wise, how much space would this take up? My terrain is composed of ~1,000,000 triangles, *3 that gives you 3,000,000 vertices. Since my game is a run-and-shoot-esque FPS, the only really collisions that would occur would be between the players and the terrain.
Collision shapes can be shared between multiple collidables. So, while you can't add the same Entity or Terrain or InstancedMesh to multiple spaces at the same time, the collision shape used by the objects can be used by multiple collidables which each reside in a different Space. This would save you from having to repeat millions of triangles.

(Watch out, though: the StaticMesh's acceleration hierarchy is associated with the StaticMesh itself, not its shape. If you are concerned about memory, use an InstancedMesh instead. InstancedMeshes store the hierarchy in the shape.)

So, assuming there's a reasonable quantity of players, using separate spaces is perfectly doable. Secondary overhead from redundant Space structures will be insignificant compared to any content. Of course, objects in different spaces will not interact, so you'd have to handle intercharacter collisions and interactions manually somehow. You'd no longer have access to a unified ray casting acceleration structure that covers all characters, either; you'd have to set up your own (perhaps an orphaned DynamicHierarchy broad phase, or if you need it, a specialized implementation that only handles raycasting and nothing else).
I've also read online that the physics engines should be run at a fixed timestep - that is to say, you have an accumulator that fits as many dt chunks as possible in the elapsed game time, and saving the remaining fractional dt for the next frame. I don't see how this could help though - wouldn't the lack of processing the fractional dt create occasional jumps in the game, and if a player's computer lagged, wouldn't everything blow up?
Fractional dt's are handled using graphical interpolation. BEPUphysics has interpolation buffers for this purpose.

If the player's computer lagged momentarily, it will have to work hard to catch up. BEPUphysics enforces a maximum on the number of timesteps that can occur in a single update to prevent your computer from locking up too horrendously. It defaults to 3 time steps, though it can be configured. So, if the computer stalls for a quarter second, the simulation will essentially run at 3x speed until it catches up again.

However, if the computer is too slow to run the simulation in real time on average, it will cause a vicious loop. Every update, it will fall further and further behind. There is no way out of this situation except for making the simulation cheaper or getting a faster processor. Turning off fixed time stepping will make things feel more responsive since only one time step is running in each update instead of 3 (or whatever the max is set to), but the simulation will still fall behind if the CPU cannot run it fast enough.

Giving the engine a variable time step can escape the issue, but at a huge stability loss. If the computer is slow, then the time steps are going to be very long. Long time steps- especially those of varying length- are the bane of robust simulation.

___
My usual approach to networking is just to give the client a little more authority and, if necessary, add a few heuristics to the server for security purposes. It's not as rock-solid from an anti-cheating standpoint and introduces some other event-timing issues to handle, but it can loosen up computational and bandwidth requirements hugely. On top of that, the assumption of even a little bit of trust tends to simplify everything. Some form of this is pretty much required for a smooth experience in many-player games. It works well enough for World of Warcraft :)

Re: Networking Physics

Posted: Sat Jan 19, 2013 9:51 pm
by _untitled_
Thanks for the quick reply!

I think I'll try the multiple spaces approach.
Collision shapes can be shared between multiple collidables. So, while you can't add the same Entity or Terrain or InstancedMesh to multiple spaces at the same time, the collision shape used by the objects can be used by multiple collidables which each reside in a different Space. This would save you from having to repeat millions of triangles.
Does this mean that I can't simply create the StaticMesh, and add it to all of the player's spaces?

Re: Networking Physics

Posted: Sat Jan 19, 2013 9:54 pm
by Norbo
Does this mean that I can't simply create the StaticMesh, and add it to all of the player's spaces?
Correct. Space objects can only belong to one Space at a time.

Re: Networking Physics

Posted: Sat Jan 19, 2013 10:01 pm
by _untitled_
Could you give me a code example of how to achieve it, then? I'm quite new to this library (just started messing around with it yesterday).

Right now, this is what I'm doing (a global space)

Code: Select all

buildChunk()
{
            // generate vertices, etc.

            _world.RemoveMesh(c.PhysicsMesh);

            c.PhysicsMesh = new StaticMesh(c.vertexVectors.ToArray(), indices);

            _world.PhysicsSpace.Add(c.PhysicsMesh);
            _world.PhysicsDebugDrawer.Add(c.PhysicsMesh);
}
Ideally, I would want to be able to store a global list of Physics spaces, index 0 being the "global" space, which would have the terrain and non player objects like grenades and rockets, index 1 being player 1's space, which would have player 1's physics body, the terrain, and the same non player objects like grenades and rockets, index 2 being player 2's space, etc.

This would allow me to check for collision between players and non-player objects like grenades and rockets by simply attaching a hook/event for objects like grenades/rockets so that they would be able to interact with players. Player and player collision is something I'm willing to give up.

Re: Networking Physics

Posted: Sat Jan 19, 2013 11:02 pm
by Norbo
For InstancedMeshes in particular, check out the InstancedMeshDemo in the BEPUphysicsDemos for an example. It comes down to creating an InstancedMeshShape, and then passing that InstancedMeshShape into however many InstancedMeshes you want. Each InstancedMesh can belong to one Space, but there's only one InstancedMeshShape in existence. That prevents redundant hierarchies and vertex data.

Duplicating bunches of entities works similarly, though it's a lot less meaningful to share shapes between simple entities. Check out the EntityConstructionDemo in the BEPUphysicsDemos for an example. It's probably not even worth it to bother- just creating duplicate full Entity objects would probably be a little more convenient.

As for creating a bunch of separate spaces, it's not any different than managing one space as far as each space is concerned. It would be wise to not give each Space.ThreadManager its own threads, and instead update the separate spaces in parallel for slightly better performance.

However...

If there are many objects- particularly dynamic ones like rockets and grenades- which need to be duplicated across many spaces, the value of splitting spaces goes down extremely rapidly. At that point, splitting spaces is not much more than a really complex collision filter between characters.

Presumably, all state is stored in a sliding window for all objects to allow rewinding to occur. This data must be available for every object in the space, and for a single player's space, every object must be rewound and resimulated.

If the number of rockets, grenades, or other objects duplicated between simulations is very small, this could appear to be an optimization in comparison to rewinding and replaying everything together. However, consider what happens when dealing with multiple players at once: duplicate simulations. Assuming a reasonable update rate, it seems likely that this situation will arise relatively frequently.

Since you already have universal state stored, you could rewind and replay the whole simulation- every player and object included- at once. If there are multiple pending input updates to process, they can be processed together. This has some advantages:
1) Produces more informed result in the end since more of the simulation is included for consideration.
2) Provides the option to include direct character-character interaction.
3) Potentially faster than a bunch of parallel rewind-replay simulations doing redundant work.
4) Don't have to go through all the tedium and bug-prone code necessary to split simulations into a bunch of spaces.

In other words, it might be counterproductive (and certainly more complicated) to try and isolate the updates of individual objects.

Re: Networking Physics

Posted: Sat Jan 19, 2013 11:14 pm
by Norbo
I should also mention something else that crops up in networking frequently:

Avoid relying on perfect determinism. While it's possible to get perfect determinism (on a single computer, anyway), it requires a lot more effort to ensure than it seems at first glance. There is a bunch more state than just position and velocity that needs to be managed to keep things deterministic. Even the order of collision pair generation can change the result.

With no effort expended to ensure determinism, the simulation will just produce 'similarly valid' results; on short timescales where significant divergence doesn't have a chance to accumulate, this works fine. Just don't rely on long term consequences of tiny results.

Re: Networking Physics

Posted: Sun Jan 20, 2013 12:32 am
by _untitled_
I wouldn't be splitting spaces on the client (the client rewinds and replays), but the server.
I see this is useful on the server because I could update each player independently with their own timestep (this would get rid of the problem of time synchronization between individual clients and the server). Then, if a grenade spawns, would add a sphere object to all of the spaces, and that way I could have the sphere collide with players.

If I were to use a global space on the server, what I see as a problem is time synchronization between the server. What happens if a player presses "w" to move forward for 1 second, but because of lag, the packet arrives after the 2nd interval and the server processes it for 2 seconds? The data is completely off then.

Re: Networking Physics

Posted: Sun Jan 20, 2013 1:34 am
by Norbo
I see this is useful on the server because I could update each player independently with their own timestep (this would get rid of the problem of time synchronization between individual clients and the server). Then, if a grenade spawns, would add a sphere object to all of the spaces, and that way I could have the sphere collide with players.
Without the full context of the networking model, I unfortunately cannot speak of specific solutions. I do suspect that there exists an implementation using a single space which is compatible and less complex than the multi-space approach.
If I were to use a global space on the server, what I see as a problem is time synchronization between the server. What happens if a player presses "w" to move forward for 1 second, but because of lag, the packet arrives after the 2nd interval and the server processes it for 2 seconds? The data is completely off then.
Any system which simulates forward based upon possibly desynchronized data will inevitably desynchronize and require correction of one kind or another. The only way to avoid this fundamental requirement is to not simulate beyond known, immutable data.

If you plan to use the separate spaces in such a way that they never simulate beyond a fixed history, then this isn't an issue. It seems probable that an analogous implementation using a global space could exist in most such cases. I don't know the specifics of your implementation, so I can't say much more than that.

Re: Networking Physics

Posted: Sun Jan 20, 2013 2:58 am
by _untitled_
Thanks for the help.

I think I'll try the multiple spaces approach first and see how it goes.
One more question: If I were to create a sphere object for a grenade, add a subscriber function to that sphere object for collisions, and add that object to all player spaces and the global space, would it work? (work as in receive collision events from different spaces)

Re: Networking Physics

Posted: Sun Jan 20, 2013 3:08 am
by Norbo
Dynamic spheres, which are entities, can only belong to one Space at a time. More generally, all ISpaceObjects can only belong to one space at a time. Anything passed into the Space.Add or Space.Remove function is an ISpaceObject. (As for why, it is assumed that ISpaceObjects are somehow modified by the Space which owns them. For example, a sphere is simulated by its owning space. If it were able to exist in multiple spaces, it would be simulated by all the spaces, causing severe conflicts of one kind or another.)

So, the sphere entity would need to be duplicated for each space, and an event would need to be hooked on each of the duplicates.

Re: Networking Physics

Posted: Sun Jan 20, 2013 3:09 am
by _untitled_
I see. I guess lists will be my best friend for the next hour or so! :)

Thanks for the help!