🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Part 3: UI and Network

posted in trill41 for project ABx
Published August 31, 2018
Advertisement

Preface

Sorry for the weird order, this is partly chronological and partly what came out of my mind.

UI

I'm not really a frontend guy, give me some backend service nobody will ever look at, and I'm happy. But since RPGs usually have a rich GUI (Chat, Party, some kinds of Maps, Options etc.) and I'm doing it alone, I'll have to do it.

After messing around a lot with Urho3D's UI, I think slowly I get used to it. I even tried Nuklear but realized it's not what I needed due to its immediate mode nature, and the code ends up to be a bit spaghettiish.

With Urho3D I can create the UI with the Editor, save it as XML file and load it at runtime, subscribe to some events and it's done. It's even possible to combine several windows into one complex window. For example, the Options window consists of six windows: The container with just the tabs (taken from Urho3D-UI-Components) and each tab is a separate window.

So far we have:

  • a fully working Chat window with the different channels,
  • a partly working Options window with fully customizeable shortcuts and multiple shortcuts per action,
  • a Party window and Mission Map that's not working at all,
  • a fully working Mail window and compose New Mail window (except that the multiline edit still bothers me a lot),
  • a fully working Game menu,
  • something that shows the Ping to the server and other things.

abui.thumb.png.6ae3ecc7f62e99c774363620e5a3dc3c.png

Network

Some details about the network layer. As mentioned earlier this is not a fast game, like an action game or a shooter. That's why I chose TCP over UDP. Using TCP takes out a lot of problems, like packet losses, wrong order of packets. With TCP, packets are always received in the right order, or something goes terribly wrong, e.g. disconnects. Of course this comes at a price (no advantage without disadvantage!), higher latency. But for slow games it may not matter so much.

Update rate

You know that interactive programs execute an endless loop. An interactive console program could look like this:


void main()
{
    bool running = true;
    while (running)
    {
        std::string input;
        std::getline(std::cin, input);
        if (input.compare("quit") == 0)
            running = false;
        else if ...
    }
}

A Windows program looks usually like this:


void main()
{
    MSG msg = { 0 };
    while (msg.message != WM_QUIT)
    {
        if (::PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE))
        {
            ::TranslateMessage(&msg);
            ::DispatchMessageW(&msg);
        }
    }
}

A game isn't much different:


void main()
{
    while (the_game_is_running)
    {
        // Update game state
        Update();
        // Render the frame
        Render();
        // Wait to meet the desired frame rate.
        // If vertical synchronization is on, the Graphics API may do this.
        WaitSomeTime();
    }
}

This game server does it similar, the games have an Update() method which is executed from time to time. The difference is that a game server does not update the game state in an endless loop and waits most of the time, but it uses a Scheduler. It would be a waste of time when it sleeps most of the time, it can simulate other games (or do something completely different).

The game update method of this game server looks a bit like this (simplified):


void Game::Update()
{
    // Dispatcher Thread
    int64_t tick = Utils::AbTick();
    if (lastUpdate_ == 0)
        lastUpdate_ = tick - NETWORK_TICK;
    uint32_t delta = static_cast<uint32_t>(tick - lastUpdate_);
    lastUpdate_ = tick;

    // First Update all objects
    for (const auto& o : objects_)
    {
        o->Update(delta);
    }

    // Send game status to players
    SendStatus();

    // Schedule next update
    const int64_t end = Utils::AbTick();
    const uint32_t duration = static_cast<uint32_t>(end - lastUpdate_);
    // At least SCHEDULER_MINTICKS
    const int32_t sleepTime = std::max<int32_t>(SCHEDULER_MINTICKS, NETWORK_TICK - duration);
    Asynch::Scheduler::Instance.Add(
        Asynch::CreateScheduledTask(sleepTime, std::bind(&Game::Update, this))
    );
}

The server runs the simulations every 50ms (NETWORK_TICK = 50), this are 20 simulations per second. The client runs updates every ~16ms (60FPS) or ~8ms (140FPS) or whatever frame rate it is running.

The client sends all collected packets (e.g. player inputs) all 16ms (60 times per second) to the server, no matter if it runs at a higher frame rate (lower frame rates are a problem at the moment, that needs to be addressed...). The server collects all this inputs from the client and puts it into a queue, which is processed in the next update to calculate the next game state.

Delta compression

Delta compression means the server does not always send the whole game state to all clients, but only what has changed since the last state. This reduces bandwidth usage drastically. Since we use TCP we can assume that the client always knows the previous game state, so it's safe to send only the difference.

This is the only compression it uses. The packets are small binary packets and may not compress well, so it's probably not worth the CPU cycles.

Client/server asynchronicity

There are mainly three methods to address the problem that client and server are asynchronous, which is caused by different update rates (20 updates/sec on server, 60 updates/sec on client), network latency, server load etc.:

  • Entity interpolation is already done with Entity Position Interpolation.
  • Input prediction is not yet done.
  • Lag compensation/Server reconciliation will not be done. This is more important for fast games.

Further reading

In no particluar order.

0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement

Latest Entries

Advertisement