I've found a new way to do game timing...

Blitz3D Forums/Blitz3D Programming/I've found a new way to do game timing...

sswift(Posted 2004) [#1]
They say neccessity is the mother of invention...

While working on my tank game, I ran into a little problem. In order for netplay to work properly, I need my physics simulation to run the same on different PC's.

With delta timing, the time for each physics frame varies. One frame might take 1/60th of a second, the next, 1/58th.

Now normally this is good enough. The game will run pretty much the same on different PC's. But with this method, tiny floating point errors can add up. On one PC, a bullet might hit a corner and bounce off it. While on the other, that bullet might just barely clear that corner and bounce off an entirely different wall, resulting in a miss of an enemy tank.

Also, using delta timing means that one cannot easily record demos, because when you play back the demo, the frames won't take exactly the same amount of time between each that they did when recording the demo.

Now, the other method one can use to time their game is frame tweening. In tweening, every physics loop is calculated for the same length of time. But since you're not calculating a new object position every frame, you have to tween the object positions between frames. But this leads to all sorts of headaches because you object transparency gets tweened as well, and hiding objects and such might not take place exaclty when you expect it to, and collisions can sometimes act funny as a result of this.





My new method has the benefits of each of these methods, in exchange for one drawback.

My method is as follows. For each frame, calculate the amount of time the frame took, just as one would do with delta timing. Then, and here's the trick... Divide this time into discreet chunks of fixed time. Then retain any remainder, and add that to the time for the next frame.

Here's an example.

I calculate a frame of graphics. It takes 17 milliseconds to render. On my next frame, when I calcualte the physics, I divide these 17 milliseconds into chunks which are 4 milliseconds each. For each 4 millisecond timespan, I calculate my physics once. Thus every physics loop is done on a 4 millisecond chunk of time on every PC. Then, because the frame time was not evenly divisible by 4, I have one millisecond left over, which I carry forward to the next frame. The reason I do this is so that I don't lose a bit of time every frame resulting in the objects moving more slowly. For example, if my framerate was 60fps, and my time chunks were 10ms, then if I did not carry forward leftover time, I would lose 6ms of movement time every frame... My objects would move 33% slower than normal as a result. But by carrying forward the leftover time, I avoid this problem.

But carrying forward leftover time can result in choppyness. That is why I only carve time into 4ms chunks. One cannot percieve any differences between frames in how fast a camera is scrolling over a scene even when it is scrolling very slowly with such small time chunks. However, if one has a first person shooter, one need not have such precision. One could then carve time up into 16ms chunks perhaps, one for each frame at 60fps, and get away with it, not noticing any choppiness as a result, because choppiness is much harder to detect in an FPS than a scrolling game.

Now, the drawback of this method, is that one may need to calculate their physics four times a frame if the game renders at 60fps, and they will need to calculate the physics 8 times per second at 30fps, and 16 times per second at 15fps. Unfportunately it is the slower systems with lower framerates that would suffer most from having to calculate the physics more than once per frame. However, the physics in Blitz seem pretty fast, and calculating them 16 tiems per frame on a system which runs your game at 30fps might not actually impact the framerate much.

But while this method is not perfect, it does provide the benefit of physics running at a constant rate, while avoiding the icky perils of frame tweening. And it is very very simple to plug into a game which already uses delta time. Just make sure to keep the non physics stuff like getting keyboard input and updating shadows, or skyboxes, out of the physics loop, and correct the delta_time# variable whatever you call it after you mess with it for updating the physics so your other stuff will still get the correct time per frame.

Here is the main loop of my tank game currently as an example of how to do this.




Braincell(Posted 2004) [#2]
I thought you fire the bullet, you tell the server, it calculates what happens to the bullet and tells the client. Isn't that how it works?

Edit: otherwise, a nice idea, i'll have to read more into it


sswift(Posted 2004) [#3]
"I thought you fire the bullet, you tell the server, it calculates what happens to the bullet and tells the client. Isn't that how it works?"

Well you can code multiplayer that way. And that way makes it more difficult to cheat. However that way also introduces a lot of lag into the gameplay. My tank game uses a server based architecture, but with trusted clients.

For example, the clients in my tank game move about as they would if they were playing the game locally. Then, each time the user changes the input they are providing, which generally happens less than five times a second, the client tells the server what inputs are currently active, where it's tank is, what direction it is facing, and how fast it is moving. This allows the client to move completely smoothly on their end, even when playing over a modem. When playing FPS games like Wolfenstein over a modem, you will find that your movements are not smooth. You jump around because the server mispredicts where your own inputs placed you. So it corrects your location. In my setup, the client is never corrected. The client corrects the server. And because every single change in direction is sent to the server, the simulations of playet movements are 100% precise. There is no player warping when there is a lot of lag. The main side effect of lag is that the players may see themselves in a different location than the other players see them. The more lag, the more discrepency there is.

Unfortunately this means that a bullet that one player thinks missed them, may actually hit them on the server side. Now, either you have the server make the decision about who was hit and who was not... Which will make you be hit by bullets you thought did not hit you, or you have the clients tell the server when they themselves were hit, which will make bullets you fire appear to do no damage to some enemies you think you hit, and damage other enemies you think you missed.

This is a problem in completely server based games too though. Most FPS's avoid this problem though through trickery. They do not tell you how much damage the other players have taken. And they use invisible bullets for most weapons, so you can't really tell if you hit the enemy players. And when they do show that you hit an enemy, it might only be blood spatters, which don't give you a very precise idea of exactly how many bullets actually hit their mark. And speaking of bullets... You fire lots of them at once, except with sniper rifles, and the damage from most weapons is spread out over a wide area, so that even if you miss with your rocket, or some of your bullets, they still end up taking some damage.

My game unfortunately does not allow me to do these tricks, so I need to reduce lag as much as possible and figure out what will annoy the player least. And probably a player being hit by a bullet they though missed them would be more annoying than a bullet they fired not damaging an enemy player or a bullet that missed damaging the enemy. So I will probably have the clients tell the server when they have been hit by a bullet rather than the server telling the clients who has been hit. The server will simply pass along the information to the other clients that one has been damaged.

Of course as I said, this can make it easier to cheat, but my secret weapon against that is that the game will only have a few people in it at once, and the game will allow the player who is the server to ban other players from the game. And there won't be any servers running with nobody manning them to watch for cheaters. Plus my game won't be near as popular as Half Life so nobody will be likely to write any cheats for it.

Anyhow, to get back to what this new timing method is for... Basically as I said in the post above, I wanted to stop bullets from appearing to bounce off a wall on one system and miss the wall entirely on another. Now, I could code the server to keep track of when bullets hit a wall, and tell the clients to spawn a new bullet there traveling in a new direction, but that would be prone to lag, and bullets would appear to stop when they hit a wall for a moment. Also if I had the server tell the player where their bullet was fired from that would result in bullets appearing away from the tank turret, and after a short delay, in some cases, again, because of lag.


Braincell(Posted 2004) [#4]
I'll be into multiplayer soon, so this is interesting for me. Though bare in mind i have only basic knowledge, but enough for now I think. So you said:


The main side effect of lag is that the players may see themselves in a different location than the other players see them. The more lag, the more discrepency there is.



The net code that i liked most as player was in Counter Strike. All players depended on the server sending them info, and i had to wait for the server to tell me where i was. It does not calculate where i move, but it listens to input in some intervals. If there is no input for a while, then you have to wait. So when i shoot somewhere, i wait and then i see the shot fire, but i also see exactly where it fired. I also see the players in their positions where everybody else sees them, provided we all have no lag or same lag, and the server lag is the main problem. I also understand that client lag is the main cause of the server lag, and that it isn't all about bandwidth, its about hops and about the way that data comes in, etc. etc. So looking at this, i would say you would still have the same amount of discrepancy as doing the normal way, only it would be different kind. You always have to have lag, you just cant code it away. But if i understand your goal right, maybe you could do the same thing server-wise. Meaning, the server decides who needs to know what and sends the appropriate data only. If a tank is offscreen and is unlikely to appear in the next few seconds, don't send any kind of info to the client where it is.

I think what you are going for was in Delta-Force. I would always fight sniper-wars there and it was so annoying when i see the enemy sniper just miss me, only to die a few seconds later. I would rather have choppy movement than that.

Also, in Team Fortress Classic, you could see some bullets fly. What they did there is same i think as in CS. You fire the bullet, you wait for the server to pick it up, then it responds to you as well as to the player you're hitting where that bullet left. But there was another thing they used too. If you fire for example, and keep moving, you would see bullets actually flying from behind you (if moving straight) which was OK to me. So movement is partially-client-based and shooting is server-based i believe. Partially-client-based i mean because you can move without being chopped or delayed, but if you don't respond to the server long enough it teleports you. Other players see nearly what you see in terms of movement, or rather a "ghost" image slightly behind you. If server lags up during your movement, in their eyes you stay put, and when it comes back, you appear somewhere else - where you were standing in your own game, as a client. If the lag is too long, the skipped movement would be too long, and the server puts you where it thinks you should be. Thats what i figured happened anyway, i might be wrong, but its at least a smart way of doing it, again in my opinion!

BTW, why would you even tell others that someone has been damaged? OK if you want to change appearance of the tank when its hit, but maybe only send it when appearance change happens, which shouldn't be often.

And you said:
Also if I had the server tell the player where their bullet was fired from that would result in bullets appearing away from the tank turret, and after a short delay, in some cases, again, because of lag.


which is i think the best option, as mentioned above. :)

Looking forward to some demos!


sswift(Posted 2004) [#5]
"I think what you are going for was in Delta-Force. I would always fight sniper-wars there and it was so annoying when i see the enemy sniper just miss me, only to die a few seconds later. I would rather have choppy movement than that."

That would be the case if the SERVER decided who was hit. But as I said above, it would be less annoying to players if the CLIENTS decided if they were hit. So your client decides if you were hit, and then tells the server, which then informs the other clients.

This way, you are only hit when you see yourself hit.

The flip side is that you might see yourself hit someone else, but they don't detect the hit, so they don't take any damage. Which is annoying, but not as annoying as being hit by a bullet you thought missed you. In addition, you might see a bulet you fired miss an enemy, but then he takes damage from it. This might surprise you... But it won't annoy you. And it won't annoy them, because they'll have seen the bullet hit them.


"BTW, why would you even tell others that someone has been damaged?"

Because in my game each tank has a damage meter that you can see, so you know if the other player is hurting. And as you said, to show tank damage. Also the game needs to know when to make a tank explode when hit. There are several ways to do that like everything else, so the client might need to know that in some cases. I decided not to actually make the tanks appear damaged in the end though. I was going to make them smoke and make broken engine noises, but the engines are annoying when they are loud enough to hear easily, and the smoke particles could cause slowdown and it just didn't look good.

"Looking forward to some demos!"

There is a demo in the generqal forum in the thread about how much you've made from Blitz. But you'll need to find someone to play multiplayer against to actually fight anyone... you can drive around though. And shoot non moving enemy tanks.


Braincell(Posted 2004) [#6]
Ah, so you make bulets server-side, and damage client-side? Interesting. Might work. Should work.


slenkar(Posted 2004) [#7]
Ill probably have to come back to this thread in 2 years when I understand it, but....thanks!


sswift(Posted 2004) [#8]
"Ah, so you make bulets server-side, and damage client-side?"

Not exactly. The damage is client side, but the bullets are as well. When a client fires, they simply tell the server where they fired from, at what angle, and what type of bullet they fired. This means the bullets always come out of the tank turrets. But is also means that a rogue client could spawn as many bulelts as they want from any location. :-)

But it's not like server based solutions are much better. When playing counterstrike I have encountered people doing things that I would have though impossible on a server based architecture. Things like "speed hacking" where one can run super fast, as well as fire super fast. Or flying about. Or walking through walls.


Rob(Posted 2004) [#9]
Server based solutions work best, why are you re-inventing the wheel into a square shape?


Genexi2(Posted 2004) [#10]
So how would this work on a system where the frame-rate is never constant, or uses a laggy connection?


sswift(Posted 2004) [#11]
Because they DON'T work best?

Problems with pure server based architecture:

1. Clients on modems find that their input lags, or that when they move, sometimes the server moves them back. When the lag is very bad, sometimes they will run up a hall, only to suddenly warp back to the start stuck against a wall.

If you have high speed internet you might not realise this is the case, but that is how gameplay was for me on a modem when playing Wolfenstein only a year and a half ago.

In a third person game, especialy a tank game where the characters are only supposed to move forward and backwards and turn smoothly, this client-local warping would look terrible.

My method does not suffer from this, even with very high pings.


2. Players with high pings appear to warp about the map, sometimes dissapearing and reapparing in new locations far from where they were.

Again, my method does not suffer from this. Players NEVER warp. They almost always move exaclty as they would if they were playing locally. Only lost packets can result in warping, and that happens very rarely.


3. Clients experience lag when moving as stated above, but they also experience lag when firing. Player pushes a button, and nothing happens for 200-400ms as message goes to server and comes back. Games like Half Life hide this by making you SOUND like you're firing, but you realyl don't start firing for 200ms, or however long it takes the message to get to the server. My tank game however fires single bullets. I can't just play a sound of the player firing. I have to show a bullet coming out. But if the bullet's location is dictated by the server then it won't start moving for 400ms if your ping is 200ms. That would look stupid. And bullets would appear out of thin air after your tahnk has moved on... Unless your tank is still sitting there 400ms later because you can't move until the server tells it it has moved.

4. The best way to code a server based system is to have one set of functions for doing all the things that the network dictates. Like firing. And those functioons would handle all the motions of objects and the spawning of them. But I am using BlitzPlay Pro, and that cannot broadcast a message to all players which also goes back to the server itself. So I need to have seperate functions for performing the same actions locally as I need the net to perform. Naturally I want to reduce code duplication as much as possible, lest I indtroduce bugs from things changing in one function but failing to be changed in the other. The only alternatives here would be to code some sort of messaging system on top of BlitzPlay Pro, to send messages to the server itself that the server sends, but this would cause all sorts of headaches.... And fixing BlitzPlay Pro is not an option as it is very complex. And writing my own netplay lib that does all the things Blitzplay Pro does would take months. As would swithcing to a new lib if a better one existed.


sswift(Posted 2004) [#12]
"So how would this work on a system where the frame-rate is never constant, or uses a laggy connection?"

Uh... That's what it is designed for. This method is like the delta time method. Frames can take a long time, or a short time. And a laggy connection would not affect it, because the positions you boradcast would be calculated from the same physics system which uses fixed time increments.

In other words, without this method, on my system tank A says they are firing from 10, 10. They say they are firing at a 45 degree angle. On my system, I get this, and I simulate that firing. But on my system, because the time between physics frames varies, the bullet they fired hits the wall at a slightly different location on my system than on their system. They calculate it hits the wall after 1.1 seconds have passed, I calculate it hits after 1.01 seconds have passed. The difference is slight, but a slight difference means on my system the bullet hits a corner, and on theirs it hits the flat part of the wall. The bullets on each system go at different angles.

But with fixed physics time intervals, on both systems the bullets move exactly the same distance each physics frame. There is no way for them to move differently on each system. It is of course, still possible that on my system a player gets in the way of the bullet and on theirs it does not, but at least the bullets will not bounce off the walls at entirely different angles.

Plus with this method you can record gameplay demos and play them back.


jfk EO-11110(Posted 2004) [#13]
I see this is a very nice idea to synchronize the gameplay of diffrent machines, but there is still one problem: even if the player 2 was notified about the exact actions of player one, he will know it not in realtime, so there will be a lag. You can try to compensate this with prospective guessing, cubic spline interpolation etc. but this will again result in diffrent physical details etc. IMHO it would be better not to do the physics on all machines, but only on one computer and only tell the other machines what happened. So eg. each machine could calculate its own bullets and then only send their positions etc. There would of course still be a lag, but at least the bullets would act the same way everywhere.


martonic(Posted 2004) [#14]
sswift: I applaud your patience explaining all this - as well as your thoughtfullness toward user-friendly solutions.

One thing occurs to me that might reduce the artifacts caused by lag. This is to have the clients share tank velocity information as well as tank position, to have each client interpolate the positions of other clients' tanks based on that, and to have the tanks accelerate slowly and have a wide turning circle, so that changes in velocity are sufficiently time-consuming to allow each client to keep up despite moderate lag. So long as all clients agree closely on tank positions, the bullets will take nearly the same paths and cause nearly the same damage, as seen by all clients. Slow acceleration and wide turning seems realistic for tank movement.

I have experience with multi-server games. Although routing problems are occasionally severe, most lag occurs in connections to remote places like some locations in asia and africa. In that case, lag can be horrible, frequently around 5-10 seconds and sometimes measured in minutes! However, if in any single game, your players are all either in North America or Western Europe, or even in South America, then in almost all cases the lag from each player to the server will be about 100-150 ms (one-way) for dialup, 20-30 ms for DSL, and only about 5-10 ms for cable Internet connections.

Good luck with what I expect will be a fine game.