Search code examples
c++sortingserverclientonline-game

Is it better to sort from server and distribute to clients or send unsorted and let clients sort it?


This is an online game and I was paid to implement a game event, which is a Player versus Player game system.

In my design I have a server side class (named PvpEventManager which is the event manager and it processes when a player kills another one, when a player joins or leaves the event, be it by decision, by being disconnected...etc, and has many other functions.

Now, this class also holds a container with the player information during the event (named vPlayerInfo), for all kinds of processing. When a player kills someone else, his kill must be increased and the victim's death too, quite obviously. But it also happens that clients have a scoreboard and since it's the server job to process a kill and tell all other clients connected on the event about this, the container will get updated.

It is necessary that the container be sorted from kill struct member from ascending to descending order so that the scoreboard can be rendered (at client) properly.

What would be better?

  • To sort the container at server increasing server work and send the already-sorted ready-to-render-at-screen container to all clients.
  • To send the container unsorted and let every connected game client sort the container itself when receiving it.

Note that the server processes thousands of thousands of packets incoming and outcoming every tick and really processes A LOT, A LOT of other stuff.

This somewhat describes the design of it:

Event Design

This code describes what is being done when sorting the container on part of the actual code.

#include <iostream>
#include <array>
#include <vector>
#include <map>
#include <algorithm>

struct PlayerScoreBoardInfo
{
    std::string name;
    unsigned int kill, death, suicide;
    unsigned int scorestreak;
    PlayerScoreBoardInfo()
    {
        kill = death = suicide = scorestreak = 0;
        name = "";
    }
    explicit PlayerScoreBoardInfo( std::string strname, unsigned int nkill, unsigned int ndeath, unsigned int nsuicide, unsigned int nscorestreak ) : 
        name(strname), kill(nkill), death(ndeath), suicide(nsuicide), scorestreak(nscorestreak)
    {

    }
};

class GameArenaManager
{
private:
    GameArenaManager() {}
public:
    std::map<u_long, PlayerScoreBoardInfo> m_Infos;
public:
    static GameArenaManager& GetInstance()
    {
        static GameArenaManager InstanceObj;
        return InstanceObj;
    }
};

template <typename T1, typename T2> inline void SortVecFromMap( std::map<T1,T2>& maptodosort, std::vector<T2>& vectosort )
{
    std::vector<T1> feedvector;
    feedvector.reserve( maptodosort.size() );

    for( const auto& it : maptodosort )
        feedvector.push_back(it.second.kill);

    std::sort(feedvector.begin(), feedvector.end(), std::greater<T1>());

    for(const auto& itV : feedvector ) {
        for( const auto& itM : maptodosort ) { 
            if( itM.second.kill == itV )  {
                vectosort.push_back(itM.second );
            }
        }
    }
}

int main()
{
    GameArenaManager& Manager = GameArenaManager::GetInstance();
    PlayerScoreBoardInfo info[5];
    info[0] = PlayerScoreBoardInfo("ArchedukeShrimp", 5,4,0,0);
    info[1] = PlayerScoreBoardInfo("EvilLactobacilus", 9,4,0,0);
    info[2] = PlayerScoreBoardInfo("DolphinetelyOrcaward", 23,4,0,0);
    info[3] = PlayerScoreBoardInfo("ChuckSkeet", 1,4,0,0);
    info[4] = PlayerScoreBoardInfo("TrumpMcDuck", 87,4,0,0);
    for( int i=0; i<5; i++)
        Manager.m_Infos.insert( std::make_pair( i, info[i] ) ); 

    std::vector<PlayerScoreBoardInfo> sortedvec;
    SortVecFromMap( Manager.m_Infos, sortedvec );

    for( std::vector<PlayerScoreBoardInfo>::iterator it = sortedvec.begin(); it != sortedvec.end(); it++ )
    {
        std::cout << "Name: "   <<  (*it).name.c_str()  << " ";
        std::cout << "Kills: "  <<  (*it).kill          << std::endl;
    }

    return 0;
}

Here's a link for ideone compiled code: http://ideone.com/B08y9l

And one link for Wandbox in case you want to edit compile on real time: http://melpon.org/wandbox/permlink/6OVLBGEXiux5Vn34


Solution

  • This question will probably get closed down as "off topic". However,

    First question: does the server ever need a sorted scoreboard?

    If not, why do the work?

    If anything, the server will want to index the scoreboard by player ID, which argues for either sorting by ID (to aid binary searches) or using a hashed container (O1 search time).

    Furthermore, the ultimate bottleneck is network bandwidth. You'll eventually want to be in a position to send scoreboard deltas rather than state-of-the-world messages.

    This further argues for making the clients do the work of resorting.

    There is one more philosophical argument:

    Is sorting by anything other than a primary key a data concern or a presentation concern? It's a presentation concern.

    What does presentation? A client.

    QED