Archived

This topic is now archived and is closed to further replies.

Design Question (Identifying Unique Entities)

This topic is 5142 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm currently prototyping for a large-scale multiplayer RPG (notice how I didn't say M-M-O-R-P-G? and I'm trying to build a really solid, scaleable design. So far it's going really well, but one part of the engine that just feels "not so good" is the message handling system. I currently have a pure virtual interface called IMessage which is extended by a base class called BasicMessage. BasicMessage handles packaging, unpackaging, setting values, querying for values, etc. It is overridden by each individual message which is then just responsible for message specific details. I feel pretty good about everything up to this point. The part that doesn't feel quite right is that the BasicMessage currently has a static MSG_TYPE field which I arbitrarily override with a sequential number in each new message's implementation. I'm using this static variable to identify a message and handle the message appropriately by the other systems (MessageHandlers, etc.) This feels kludgy because each message has to be manually assigned a type ID upon construction. This type ID then has to be used in corresponding handlers on both the server and the client. It's not quite as bad as it could be because instead of using the hardcoded id, I'm using something like ChatMsg::GetType(). It's not awful and I've seen similar designs in other projects, but it just feels like this will get overwhelming as I add more and more message types. Am I being paranoid? bpopp http://www.bpopp.net/articles/view.php?id=403 [edited by - bpopp on November 13, 2003 4:34:03 PM]

Share this post


Link to post
Share on other sites
I don''t personally think it would be that big of a deal to structure them that way. Just use an enum structure to hold the id''s with a consistant nameing convention for each of the classes.

Share this post


Link to post
Share on other sites
Check out the typed message pattern.

I use a variation of it without inheritance, but Boost.Function in its place. Base Event class just stores handlers. Cheap, easy, type-safe, I don't see how life gets better:

ApplicationStartupEvent e;
e.commandLine = commandLine;
e.instance = instance;
e.trigger();


Oh, and only things that register for that message actually get it.

[edited by - antareus on November 13, 2003 5:48:52 PM]

Share this post


Link to post
Share on other sites
Cool. I thought of doing something similar but I ran into a problem. I really don''t want to have to create a separate handler for each message type (there could be hundreds and some will only be a few lines of code), which means multiple message should be able to call the same handler. Which, I think, leaves me where I am. When the message calls the Handlers corresponding HandleMessage function, how does the handler know which IMessage type it is dealing with.

I''ve seen projects that use define macros to implement run-time typing. Is this why?

Share this post


Link to post
Share on other sites
If you''re going to be serializing the messages and sending them across the network, then you need *some* way of determining the type on the other end. So unless you can guarantee that all your messages will have unique sizes, you *have* to store some value that is a ''type ID.'' Those values also have to be the same on both client and server, which is why #defining them makes so much sense.

The approach I''ve taken is to set up a std::map<int, CMMPointer<MsgFunctor> > to map message type IDs to function handlers (MsgFunctor is a special version of Functor for handlers of type void (*)(IMessage*)). I recieve a message, put it into a buffer and check the ID tag, and then send it to the correct handler. It should be simple to have multiple messages handled by a single handler that way.

Richard "Superpig" Fine
- saving pigs from untimely fates, and when he''s not doing that, runs The Binary Refinery.
Enginuity1 | Enginuity2 | Enginuity3 | Enginuity4 | Enginuity5
ry. .ibu cy. .y''ybu. .abu ry. dy. "sy. .ubu py. .ebu ry. py. .ibu gy." fy. .ibu ny. .ebu
"Don''t document your code; code your documentation." -me

Share this post


Link to post
Share on other sites
Ok, I feel better. I forgot about the serialization issue which, as Richard said, pretty much requires a unique type id of some sort. I''d still love to hear some alternate suggestions, but for now I think I''ll stick with what I''ve got (his is really just a throw-away prototype anyway).

As for the Functors, I think I''m doing pretty much the same thing. I have a IHandler interface which all of my Handlers will override. It describes a pure virtual function called HandleMessage( IMessage*) which each of the handlers will implement. Each Handler is registered with the HandlerFactory (singleton) along with the msgType I talked about earlier (using a std::map). The factory insures that there is only one instance of any given handler and handles the routing of messages to the appropriate one based on messages type.

-bpopp

Share this post


Link to post
Share on other sites