PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Monday, July 11, 2022

[FIXED] How to determine type of message in runtime?

 July 11, 2022     c++, message, networking, oop, packet     No comments   

Issue

Currently I'm writing the message handling system for my game server. I'm using double-dispatch design pattern to pick the needed handler according to message id, which retrieved from a data buffer. But I ran into a following problem: I need to determine the derived class of the message to pass it into a double-dispatch handler object. the only solution I found is to write a factory method in base class with the switch inside, that will create needed derived class according to message id.

class Message
{
public:
    void dispatch(Handler& handler)
    {
        dispatchImpl(handler);
    }

protected:
    virtual void dispatchImpl(Handler& handler) = 0;
};

template <typename TDerived>
class BaseMessage : public Message 
{
public:
    BaseMessage(unsigned short messageId)
        : id(messageId) {};

    virtual ~BaseMessage() = default;

    unsigned short getId() const { return id; }

    static std::unique_ptr<Message> create(BitStream& data)
    {
        switch (data.ReadShort())
        {
            case 1: return std::make_unique<FirstMessage>();
            case 2: return std::make_unique<SecondMessage>();
            case 3: return std::make_unique<ThirdMessage>();
            // ...
        }
    }

protected:
    unsigned short id;

    virtual void dispatchImpl(Handler& handler) override
    {
        handler.handle(static_cast<TDerived&>(*this));
    }
};

How can I improve my design to avoid big-switch statement? Thanks in advance.


Solution

You might use a std::map<short,std::function<std::unique_ptr<Message> (BitStream& data)> and allow registration of those factory functions dynamically:

std::map<short,std::function<std::unique_ptr<Message> (BitStream& data)> createMessageHandlers;

void registerCreateMessageHandler(short id,std::function<std::unique_ptr<Message> (BitStream& data)> fn) {
      createMessageHandlers[id] = fn;
}

and use it like

registerCreateMessageHandler(1, [](BitStream& data) { return std::make_unique<FirstMessage>();});
registerCreateMessageHandler(2, [](BitStream& data) { return std::make_unique<SecondMessage>();});

Your message type constructors should probably take the BitStream& as a constructor parameter.


You should consider to use a tool like google protocol buffers to define your communication protocols.
That would help a lot in properly versioning, and parsing message packets (endianess neutral) over the wire (or wireless).

In combination with e.g. boost::asio or zeromq for the transport handling, that should give you the maximum flexibility and proper mechanisms to separate the transport and semantical layers of communication.



Answered By - πάντα ῥεῖ
Answer Checked By - Marilyn (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing