1
\$\begingroup\$

i have been playing around with the NetworkPrediction sample from Microsoft. Trying to adapt it to use gameTime. The client is running without fixed TimeStep and the server is custom C# and updates a lot faster than client.

Both client and server runs this code at update:

protected void UpdateState(ref ShipState state, GameTime gameTime)
    {
        if (turnRightAcceleration)
            state.Rotation += (this.RotationSpeed * (float)gameTime.ElapsedGameTime.TotalMilliseconds);
        else if (turnLeftAcceleration)
            state.Rotation -= (this.RotationSpeed * (float)gameTime.ElapsedGameTime.TotalMilliseconds);

        Vector2 shipForward = new Vector2((float)Math.Cos(state.Rotation),
                                          (float)Math.Sin(state.Rotation));

        if (trustAccelerating)
            state.Velocity += ((shipForward * this.TrustSpeed) * (float)gameTime.ElapsedGameTime.TotalMilliseconds);

        // Update the position and velocity.
        state.Position += (state.Velocity * (float)gameTime.ElapsedGameTime.TotalMilliseconds);
    }

This seems theoretically correct, every time a value is increased or decreased its affected by ElapsedGameTime.

And this is my Server Pump:

    public void Run()
    {
        foreach (GameServerComponent component in this.Components)
            component.Initialize();

        Console.WriteLine("Server running...");

        //DateTime serverStart = DateTime.Now;
        //DateTime lastUpdate = DateTime.Now;

        Stopwatch sw = Stopwatch.StartNew();
        TimeSpan lastTime = sw.Elapsed;
        GameTime gameTime;

        while (!exit)
        {
            TimeSpan currentTime = sw.Elapsed;
            TimeSpan elapsedTime = currentTime - lastTime;
            lastTime = currentTime;

            gameTime = new GameTime(currentTime, elapsedTime);

            foreach (GameServerComponent component in this.Components)
                component.Update(gameTime);
        }

        sw.Stop();
    }

This seems theoretically correct as well. Unless there is something about time management in .NET and XNA, but i cant find anything indicating it.

But the server and client updates at different rates, and the further you get from Vector 0,0 the greater the difference becomes and close to 0,0 it works quite well. But at Vector2(-1387865f, -1158338f) the "Ship" is barley able to move. I believe this tells me the server "Clock" is running slower than the client (the ship moves slower on server than on client), but i dont understand why it would be more prominent further away from 0,0 (makes me think its the UpdateState() function I need to look at)

I dont know what to test next and I have no idea how to fix this behavior.

Please, i need ideas. Or even better, can you see something obvious wrong with the code i have?

Thank you.

Update: This are the results from some measurements, recommended from William 'MindWorX' Mariager. Im currently trying to throttle the server to get closer to the clients updates. And i think i need to look at some performance from the client as well (later), since it seems it runs slower than 60fps atm. Ill update with results.

Server updateCount 252092674

gameTime.TotalGameTime {00:09:59.9810854}

avgElapsed.TotalMilliseconds 0.0021000000000000003

(float)avgElapsed.TotalMilliseconds 0.0021

Client updateCount 24027

gameTime.TotalGameTime {00:09:55.5527941}

avgElapsed.TotalMilliseconds 24.03

(float)avgElapsed.TotalMilliseconds 24.03

\$\endgroup\$
5
  • \$\begingroup\$ Make sure you are using the same speed for your client and server. \$\endgroup\$ Aug 8, 2012 at 20:26
  • 1
    \$\begingroup\$ I don't know if it matters, but floats/doubles suffer from a larger imprecision at higher values than at lower values. It's all I can speculate on from the current question. Have you tried debugging with an update counter on both ends? \$\endgroup\$
    – William
    Aug 8, 2012 at 22:09
  • \$\begingroup\$ Ive been on this theory also, about the float conversion. Even tried to remake the UpdateState function to only convert to float when it had to, and do it as late as possible in the equation. But as expected it did not do much difference. But I did like you suggested and debugged with some counters and info from the pump. It seems the server updates 420154 times per second, the client is about 60-100 times per sec. And converting the average elapsed time to a float does loose some precision. So im going to attempt to throttle the server updates to something more humane and see what happens. \$\endgroup\$
    – EursPravus
    Aug 9, 2012 at 11:28
  • \$\begingroup\$ Slowing down the server seems to have done the trick. I knew the server ran faster then client. I just didnt think it was that much faster also that it could have that effect. If you make your comment an answer, ill accept it. \$\endgroup\$
    – EursPravus
    Aug 9, 2012 at 12:28
  • \$\begingroup\$ I added an answer with what I think was the solution, please correct me if it's wrong, so we don't get misinformation. \$\endgroup\$
    – William
    Aug 10, 2012 at 22:45

2 Answers 2

0
\$\begingroup\$

From what you said in the comment section, it appears it was an issue with the server ticking too fast and the imprecision of floats that caused the issue. It was solved by first checking and comparing the ticks of the client and server, and then subsequently slowing down the amount of server updates.

\$\endgroup\$
0
\$\begingroup\$

Since you use a completly synchronized approach to networking you need to use a constant delta for the physics calculations, else a similar outcome is not guaranteed.

Something like this:

float overflow=0.f;
// Update physics only in multiples of 120th seconds.
float timestep=1.f/120;

while([...gameloop...])
{
  timeReminder += timeDelta;
  while(overflow > timestep)
  {
    foreach (GameServerComponent component in this.Components)
      component.Update(timestep);
    timeReminder-=timestep;
  };
}

Note that the different float-implementations on the different CPUs might behave slightly different. So to get really 100% synchronization you'll need to either write your own float type (slow, but you have float precision) or to use fixed point numbers instead (fast, easy to implement)

\$\endgroup\$
5
  • \$\begingroup\$ Im trying to avoid timestep updating. But now i kinda got it anyway since i limited the server update rate it updates constant at the limit level. But i dislike fixed 60fps for PC games. \$\endgroup\$
    – EursPravus
    Aug 14, 2012 at 12:35
  • \$\begingroup\$ But what alternative would i have to "completely synchronized networking"? The server need to be authoritative. \$\endgroup\$
    – EursPravus
    Aug 14, 2012 at 12:38
  • \$\begingroup\$ It's just a constant time delta for the computions. The problem is that x*0.004 + x*0.006 might yield a different result than x*0.01 or x*0.005 + x*0.005. You can make the timestep much smaller, but that will make it use more processor time, maybe to a point that the processor isn't fast enough anymore. \$\endgroup\$
    – API-Beast
    Aug 14, 2012 at 14:42
  • \$\begingroup\$ The problem were that the server updated so fast that the precision did not fit inside a float used to track the delta (elapsedTime). But my point is, with a authoritative server, only the server calculations is really important. The difference in the clients will be corrected within the smoothing of the network predictions anyways. And even with fixed timesteps there are still de-sync issues. \$\endgroup\$
    – EursPravus
    Aug 14, 2012 at 17:30
  • \$\begingroup\$ No there are not. 1 second is 1 second, if the physics are updated with same delta the result after 1 second will be the same. \$\endgroup\$
    – API-Beast
    Aug 14, 2012 at 17:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .