Game Server Design

Pages: 123
Every single time I try to write a server for my game to enable online play, it ends up a huge, ugly switch statement, and gets error-prone and buggy quickly. Does anyone have any idea how I should design my game servers?
It really depends on how your packets are formed. For Minecraft, each packet is different depending on what you're doing. You can set a callback depending on the packet header then pass the rest as an argument of that callback specific to that packet, using a union to hold each type of function pointer.

Other than though, not much more you can do. Can you show the ugly, error-prone parts so i get more of an idea of what you don't like?
It's error prone because it's a massive branching switch statement. I want a way to encapsulate it so it's easier to manage.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct Packet
{
    uint8_t  id[4];
    uint32_t address;
    uint64_t timestamp;
    uint8_t  fields[16];
    uint32_t sizeData;
    uint8_t* data; // Incase fields aren't enough
};

// ...
switch(packet.id[0])
{
    case UPDATE:
        switch(id[1])
        // ...
    break;

    case MESSAGE:
        switch(id[1])
        // ...
    break;
}
Last edited on
Big is fine if it works! My mentor owns an ISP and we were talking about this yesterday. Do you understand the concept of latency in terms of Internet connections? For instance you could be getting 22 Gb/s but have a slower rate of exchange than someone with a 2 Mb/s connection, the width of the pipe doesn't necessarily mean you will get data quickly (request time to start of transfer time), it just means bigger bundles of data can get through "faster."

As a game developer that's a big reason to bundle as much as possible into your transfers, and that's where things like dead reckoning and other predictive methods come into play.

As far as how you design your server? Design your protocol to need less data transferred, transfer as soon as possible when you get data (so keep your code as small as possible, minimize the logic required to serve data), and don't worry about monster code as long as it is consistent.
What kind of bizzare low level networking are you doing? There is no reason to send the address and timestamp like that. All your packets should consist of a size field, followed by size bytes of data, and your high level code deserializes that data.
It's for an online game, where there will be ~30-ish players. The players have to speak to eachother. I don't want a message to be displayed twice because of UDP's unreliability.
Bump.
Why in the world would you use UDP for text chat? UDP should only be used in cases where you don't care about the unreliability. Trying to add info the the UDP packets to make them reliable circumvents the purpose of UDP entirely, as you're basically building a slower, buggier TCP.
Last edited on
Why in the world would you use UDP for text chat?

Have to comment just from seeing this as I always wanted more info about it. To stay relevant to the topic I also implement checking packet IDs as a large switch statement and it always ends up getting really annoying to handle.

Everywhere you look you see people saying never mix TCP/UDP at it causes them both to be slower as they interfere with each other (I'm no networking expert so I just take peoples word for this). This is why people recommend to use "basic" UDP for movement + reliable layer on top of UDP for chat messages etc.

Example that states this : http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/
(Is also said all over StackOverflow as well, but don't have sources atm)
Last edited on
Eh... I doubt the credibility of that statement heavily. He avoids the argumentation that one affects the other as "complicated". I feel like he's saying, "If you play DotA 2 while streaming with Pandora, one will affect the other" which is true but... not realistically a problem.

EDIT: Also, who recommends UDP for chat messages? The only time someone recommends this is if they want to add features that TCP either conflicts with (such as a custom timeout mechanism or a more optimized reliability system) or they want to be more secure (encryption of lower level things).
Last edited on
If you don't like hard-coding handling routines, there's always an SPI-based approach...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "NetworkMessage.hpp"

namespace server
{
namespace network
{
namespace spi
{
    class MessageHandlerProvider
    {
        virtual bool shouldHandle(uint8_t id) const noexcept = 0;
        virtual void handle(const server::network::Message& message) const = 0;
    };

    std::vector<MessageHandlerProvider*> providers;

    void registerHandler(MessageHandlerProvider* provider)
    {
        providers.push_back(provider);
    }
}
    bool onNetworkEvent(const Message& message)
    {
        for(auto provider : spi::providers)
        {
            if(provider->shouldHandle(message.getID()))
            {
                provider->handle(message);
                return true;
            }
        }
        return false;
    }
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/* *.dll or *.so plugin*/

#include <iostream>
namespace server
{
namespace network
{
namespace spi
{
    class TestProvider : public MessageHandlerProvider
    {
        virtual bool shouldHandle(uint8_t id) const noexcept
        {
            return true; // handle everything
        }

        virtual void handle(const server::network::Message& message) const
        {
            std::cout << "Received Message ID: " << message.getID() << std::endl;
        }
    };
}
}
}

int main()
{
    server::network::Message dummy = ...received over the wire;
    server::network::onNetworkEvent(dummy);
}


Of course, you would have to rig up a loader system, but if I recall, there's an article on this site about how to do that. ( http://www.cplusplus.com/articles/48TbqMoL/ )

Plug 'N Play network event handlers ahoy! Hope it helps.

* @LB -- I used to be 'the goto guy' for an online game that regularly had ~500 players on at any time. Meta-data like timestamps, checksums, and any other information that can be scraped up is crucial for logging, especially when a zero-day vulnerability pops up and players start exploiting a cheat.
Last edited on
Why in the world would you use UDP for text chat? UDP should only be used in cases where you don't care about the unreliability.
Well, I am building a game.

Trying to add info the the UDP packets to make them reliable circumvents the purpose of UDP entirely, as you're basically building a slower, buggier TCP.
The whole game is UDP, I don't want to use TCP just because I want to implement a chat system, it seems like a waste.

@Luc Lieber
Thanks!
Last edited on
What do you mean "seems like a waste"? The only waste here is your effort to replicate TCP in a less efficient way. With some of the networking libraries I have used, the difference between TCP and UDP is a boolean parameter.
I mean that it'd be too much work. I'm not planning on using any net-apis except for WinSock2.
So, you've intentionally decided to limit yourself to Windows while at the same time forcing yourself to reinvent a protocol by hand? Should I even ask why?
I agree that using WinSock directly is normally not the best idea (I am very cross platform supportive). I have always used SDL_net as I am using SDL for my opengl window/input/audio anyway. Unless you are using directX I would get off WinSock and find a cross platform wrapper.

I don't see how coding a minor reliability layer on top of UDP for chat commands (in a game, for something like skype you would obviously use TCP) etc is "reinventing a protocol". Why use TCP here?
You've got it backwards: the question is actually "why use UDP here?"

TCP should be the default choice, and UDP should be used in cases where information loss is acceptable.

VoIP software like Skype and Google Hangouts most likely use UDP for sound and TCP for chat. Sound is a constant stream, so occasional packet loss is acceptable. UDP is fast, so the conversation often has a low ping.

Occasional packet loss for chat is unacceptable, and reinventing the wheel to make it 'reliable' is wasted effort when TCP is perfectly acceptable. It's fine if chat messages take a long time to arrive, even several seconds is perfectly acceptable.

I thought that, assuming you read up on what TCP and UDP were, when to use TCP vs UDP was obvious basic knowledge, but apparently I was wrong. I have a bad habit of making such mislead assumptions about common knowledge - this is not meant to be offensive.

http://stackoverflow.com/q/1099672/1959975
Notice the question is "when to use UDP instead of TCP" and not the other way around.
Last edited on
I don't see how coding a minor reliability layer on top of UDP for chat commands (in a game, for something like skype you would obviously use TCP) etc is "reinventing a protocol". Why use TCP here?
as LB said, UDP with reliability would be reinventing TCP, since TCP verifies if there is packet loss whereas UDP doesn't.

when to use TCP vs UDP was obvious basic knowledge, but apparently I was wrong
well knowing something doesn't make it apparent when to use it. i see many posts of users saying to use c++ in improper places when a simple bash script would do
I thought that, assuming you read up on what TCP and UDP were, when to use TCP vs UDP was obvious basic knowledge,

Yes it is obvious, when they are used exclusively.

Google "Mixing UDP and TCP" in 1 application and you will find more people saying "ehhh maybe not the best idea" then "Yes! Separate them out depending on what is needed". So movement uses UDP, chat uses TCP, you would assume item pickups/drops uses TCP, jumping uses UDP. Why does everyone say all of this mixing is a bad idea? If it is this obvious why are games like minecraft using exclusive TCP?

This may just be a rumor someone started and has gotten repeated too many times but I would like to see how much TCP negatively effects a parallel UDP socket with a reasonable amount of people compared to UDP handling it all. (I do not have the means to test this).

Or am I misunderstanding and you are saying TCP should just be used in games completely?
Last edited on
Why does everyone say all of this mixing is a bad idea?
im going to let the experts handle this, but i would assume its along the same reasons as having a file open in two streams
Last edited on
Pages: 123