Sign in to follow this  
Omnio

Server Snapshot Rate?

Recommended Posts

My project is coded in C# using XNA. On the client, XNA handles frame rate. BUT, on the server, I'm not sure how to control my frame rate (snapshot rate). I know how to use threads and sleeps, but how do I insure the frame rate to the millisecond??? Will using threads and Thread.Sleep calls work? I've googled for some kind of clocking example or something, but I haven't found anything that seems to address this. (or at least I think) I'd appreciate any input/links/guidance or anything on that matter.

Share this post


Link to post
Share on other sites
It's not really possible to ensure framerate to the millisecond, just because of general internet quirkyness and variable latency (if a packet decides to take a different path or something), but there are some things you can do to smooth things out a bit. Unfortunately, they all have downsides.

The designers of "Age of Empires" decided that a smooth gameplay experience was more important than a fast order-response time, so they queue a few game updates to act as a buffer against internet quirkyness. Some packets will arrive late, some early, but in the long run it tended to offer a much smoother gaming experience. The obvious downside to this is the loss of order-response time, since you have to get through the queued updates before you can get to the updates that respond to your input. Of course, the impact this will have depends on your update rate. If you're updating 10 times a second, it's a huge deal.. but if you update 33 times a second, it's not such a big deal.

Another popular strategy is to use some sort of movement prediction algorithm. These are often used in FPS and online RPG games (including MMO's). The method is pretty simple.. it basically allows you to move around the world with no feedback from the server, as you would in a single player game. This allows for a much more fluid game experience, with extremely quick order response time. When the client does hear from the server, the client will use gradual correction algorithms to slowly correct the position the player is at, so they stay synchronized with the game.

This method is favored by a lot of developers, but it has downsides and can be quite annoying to users with a laggy internet connection. The biggest problem is what is known as "rubber-banding". It is when the user suffers an extreme lag spike, and doesn't recieve any game updates from the server for long periods of time. However, it can seem like there is no lag occurring at all, because they are still able to move around and make minor interactions with things in the world (whatever the devs thought fit to do on the client without feedback from the server). It's not a big deal, and probably won't affect the majority of your players (due to the prevalence of high speed internet connections), but it CAN be very annoying to people with slow internet connections.

Another thing you have to keep in mind is that if you do collision detection on your server, and someone rubber bands, they could potentially walk through walls, or to otherwise inaccessible areas, which can very easily lead to cheating. This is a really big problem with the free online FPS "Combat Arms".

Share this post


Link to post
Share on other sites
I was also thinking interpolation, but I'm thinking about how to keep the server running at a constant rate. Sorry if i wasn't clear about that. Thanks for the input about the collision detection. I'm still not sure how this will lead to cheating; could you explain that a bit more to me???

I also have some other questions, so let me try to explain everything:

Background: I'm making a project in C#, top down 2D shooter in space.

1. How to keep the server running at a constant rate???

2. I have delta compression and RLE for my game states. How do I insure that someone can use a delta packet successfully since it is made from the last game state which they might NOT have gotten due to UDP.
a. I was thinking I could keep a game state that everyone has gotten and build deltas off of it. The base game state will be updated once every game client has said they got it. This allows me to keep sending them and building off of deltas that I know everyone has.

3. Is delta compression a good idea???

Share this post


Link to post
Share on other sites
Quote:
Original post by Omnio

1. How to keep the server running at a constant rate???


This site contains very comprehensive tutorials on fixed time-step physics as well as networking.

Simplest and most robust solution is to have both, client and server, run a fixed time step update loop as described above.

Quote:
2. I have delta compression and RLE for my game states. How do I insure that someone can use a delta packet successfully since it is made from the last game state which they might NOT have gotten due to UDP.
Articles linked above discuss part of this problem.

Simple answer: on each tick, send delta state. If some client falls too far behind, gets out of sync, or when they join, send them full state.

Quote:
3. Is delta compression a good idea???
Yes. Better yet - sending delta state (just the changes from last state) as well as compressing that will help keep the bandwidth down.

Look through forum FAQ for Half Life and Quake networking (or google for them if they aren't there). They contain complete description on how such things work.

[Edited by - hplus0603 on September 14, 2009 10:08:54 AM]

Share this post


Link to post
Share on other sites
In general, you will always run slightly behind a global idealized clock on the server (but, in general, always less than one simulation tick's worth). The server loop looks something like:


timestamp last = read_timer();
forever() {
timestamp now = read_timer();
timestamp delta = now - last;
if (delta < tick_size) {
sleep(tick_size - delta);
continue;
}
while (last < now) {
simulate_one_tick();
last += tick_size;
}
}


This assumes that you're using (or targeting) a fixed time step size, which is pretty much always a good idea.

Share this post


Link to post
Share on other sites
Thanks guys. I'm still not sure how to check if a client is too far behind. Could you elaborate or show me where exactly in the article it talks about this? The main problem is if I miss just one packet, the delta states won't work. This is a major problem because this won't run on LAN so a nice portion of the packets won't make it. (10% at least??? Getting this from a Quake Model article I believe)

So, any more advice???

PS : Thanks for being helpful. You guys have really helped me a lot.

[Edited by - Omnio on September 14, 2009 5:54:34 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Omnio
Thanks guys. I'm still not sure how to check if a client is too far behind. Could you elaborate or show me where exactly in the article it talks about this? The main problem is if I miss just one packet, the delta states won't work. This is a major problem because this won't run on LAN so a nice portion of the packets won't make it. (10% at least??? Getting this from a Quake Model article I believe)


I believe you just have to live with that. And it is not that bad. For example, taking that 10% metric, for 100 packets you send, 10 will be lost, and then you'll have to send 10 full states packets. But the other 90 packets will be delta states. It's a problem, but still it is better than sending 100 full state packets.

Share this post


Link to post
Share on other sites
Quote:
Original post by Omnio
This is a major problem because this won't run on LAN so a nice portion of the packets won't make it. (10% at least??? Getting this from a Quake Model article I believe)
My test show it to usually be far less than that - less than 1% for residential cable connections in the mainland US. Of course, there are many factors which can adversely affect this, so good to plan for the worst, but the average case for modern connections is really pretty good.

Share this post


Link to post
Share on other sites
Quote:
Original post by Omnio

The main problem is if I miss just one packet, the delta states won't work. This is a major problem because this won't run on LAN so a nice portion of the packets won't make it. (10% at least??? Getting this from a Quake Model article I believe)


Usually, all packets will arrive.
Sometimes, there will be constant packet loss.
Rarely, there will be huge and frequent packet loss.

When this happens, the data is lost, and that user will have degraded usability. No way around it.


Due to latency on WAN, clients will almost certainly need to run extrapolation. When they perform an action, the local animation begins immediately, and the actions will be confirmed by server at some point in the future. In case of packet loss, this prediction will become increasingly inaccurate as the time since last authoritative state increases. Usually, after a second or two, the client will stop simulating altogether and appear to lag out.

Client will send data frequently, 10-30 times per second. Each of these packets will have a sequence number and optionally an ack/nack field, indicating which past packets it received/missed. Connection peer will use this information to determine whether to resend a packet, or send a whole new baseline state.

Make sure to read all the articles on gaffer's site linked above. They explain these topics in detail.

Share this post


Link to post
Share on other sites
Okay, thanks guys. I'm not sure what to believe about packet loss, but I'm sure their will be instances of packet loss, so I should account for that. Thanks for your input/time. I think I can manage.

Share this post


Link to post
Share on other sites
Use the C# StopWatch class. Here's a code sample of a very simple static timer that gives time elapsed in milleseconds. I used it for a 32 player shooter and it works great.

And yes, on your game server thread use Sleep(1) if you want to be nice to the CPU. But you don't have to.


using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;


//----------------------------------------------------------------
// TimeManager - gives time elapsed in ms since last server tick
// How to use: - call TimeManager.Initialize() on startup
// - call TimeManager.Update() in your Update function
// - TimeManager.timeElapsed is time elapsed since last tick
//----------------------------------------------------------------
public static class TimeManager
{

// the time elapsed since the previous server tick
public static float timeElapsed;


// the StopWatch and private variables
private static Stopwatch stopWatch;
private static float currentTime;
private static float oldTime;


//----------------------------------------------------------------
// Initialize() - call once on program start
//----------------------------------------------------------------
public static void Initialize()
{
stopWatch = new Stopwatch();
stopWatch.Reset();
stopWatch.Start();
}


//----------------------------------------------------------------
// Update() - calculates ms elapsed since last server tick
//----------------------------------------------------------------
public static void Update()
{
// save previous time
// update current time
// calculate time elapsed in ms
oldTime = currentTime;
currentTime = (float)stopWatch.ElapsedMilliseconds;
timeElapsed = currentTime - oldTime;
}


//----------------------------------------------------------------
// Reset() - reset stopwatch to 0
//----------------------------------------------------------------
public static void Reset()
{
stopWatch.Reset();
stopWatch.Start();

oldTime = (float)stopWatch.ElapsedMilliseconds;
currentTime = (float)stopWatch.ElapsedMilliseconds;
}
}


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this