Jump to content
  • Advertisement

Archived

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

SeanHowe

Messaging System

This topic is 6321 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

Hey everyone, I''m writing a gem on messaging systems for Game Programming Gems 2, so I thought I''d drop in here and check in with you guys about what you think about them, broaden my spectrum. So, where do you use them? How do you implement them? Anything else you''d like to say about them? Thanks for any input!

Share this post


Link to post
Share on other sites
Advertisement
what do you mean exactly? passing messages to 'things' (ie entities) in your game? like telling an entity to remove itself (for example)???

if so, i have a template class called CMsgTarget (for instance):

      
template<class T> class CMsgTarget
{
typedef (T::*MemberFunction)(const char* arguments);

private:
struct MessageResponse
{
const char* messageIdentifier;
MemberFunction responseFunc;
};

MessageResponse m_responses[];

public:
void PostMessage(const char* msgID, const char* args)
{ /* find proper entry in m_responses and call it's responseFunc */ };

};


then each class that is to recieve message contains one of these classes:

        
class Entity
{
/* ... */

static CMsgTarget<Entity> cmd;

void Remove(const char*);
void Foo(const char*);
};


then in the implementation file:

        
CMsgTarget<Entity> CMsgTarget<Entity>::m_responses[] = {
{"remove", Remove},
{"foo", Foo},
{NULL, NULL} //this is here so when searching, we know when to stop.

};


then, to post a message, we do this:

        
Entity someEnt;

someEnt.cmd.PostMessage("remove", "");



this is off the top of my head, so expect errors, and in the real code, there is more functionality (like climbing class hirearchies to let a base class handle the message if the derived class doesnt, etc) - but this is the general idea.

hope this is what you meant, this took like 10 mins to write
it not, oh well - i got nothing better to do

Edited by - Yorvik on January 30, 2001 7:10:01 PM

Share this post


Link to post
Share on other sites
That''s exactly what I meant, actually! Thanks a bundle! Any more posts like that by anybody else would me much appreciated as well.

Share this post


Link to post
Share on other sites
I have a class called CGameEngine that has a method:

    
CGameEngine::ProcessMessage(int cmd, void* params, void* returns);


I then wrote a wrapper around the Windows Messaging system that includes the following global functions:


PostEngineMessage(int which, int command, void* params, void* returns )
{
return PostMessage( GetWindowHandle(which), command, params, returns );
}


And one for SendEngineMessage() -> SendMessage()...

I have an EngineWinProc() function that all Engine components have assigned to their respective types.


BOOL EngineWinProc( command, params, returns )
{
CGameEngine* Engine = (CGameEngine*) GetWindowLong(..., USER_DATA);
Engine->ProcessMessage(command, params, returns);
}



Each engine type (CGameEngine*) either does or does not know what Protected Method to call based on the command and passes that method the Params and Returns. Params are used for parameters passed in and returns is used to return the results back to the original caller.

Pretty complicated really - but only moderately slower than running directly through windows messaging system (5-8% slower due to v-table lookups and class hierarchy) and ALL commands are encapsulated within the respective classes.

If you are interested in the source, email me - address is in profile - and I will send it to you as an example if you like.



Regards,
Jumpster


Semper Fi

Edit:

This provides the ability to do something such as this and seems to work pretty good for some less cpu intensive games:

  

// Post on the queue, play when you get the chance...

PostEngineMessage( itSOUND, WF_PLAYSOUND, &soundtoplay, NULL);

// Send right now and immediately return...

SendEngineMessage( itINPUT, WF_READDEVICED, &device_data, NULL);





Edited by - Jumpster on January 30, 2001 8:38:52 PM

Share this post


Link to post
Share on other sites
quote:

If you are interested in the source, email me - address is in profile - and I will send it to you as an example if you like.



same goes for me, share the wisdom n''all

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Personally, I prefer to stay away from these for a few reasons.
1. Type safety. Passing arguments with the message usually involves a void* or a CCommandParamBase* or a union of some kind. It''s error-prone since compiler cannot ensure that correct data is passed to the handler function. You can make up for it somewhat by coding preconditions in every message handler, but I''d rather not use void* at all and let the compiler do type checking.
2. Once you have central message dispatcher any object can talk to any other object. This breaks encapsulation and makes it harder to figure out execution flow.

There''s another (better, IMHO) way to sending/receiving events. COM calls it event source/sink, there are other names: observer pattern, listener pattern, publisher-subscriber, etc. Look it up if you are interested.

Share this post


Link to post
Share on other sites
AP post above is mine - just in case you want to know where send flames Sorry ''bout that - forgot to enter username/pwd.

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster

Personally, I prefer to stay away from these for a few reasons.
1. Type safety. Passing arguments with the message usually involves a void* or a CCommandParamBase* or a union of some kind. It''s error-prone since compiler cannot ensure that correct data is passed to the handler function. You can make up for it somewhat by coding preconditions in every message handler, but I''d rather not use void* at all and let the compiler do type checking.
2. Once you have central message dispatcher any object can talk to any other object. This breaks encapsulation and makes it harder to figure out execution flow.

There''s another (better, IMHO) way to sending/receiving events. COM calls it event source/sink, there are other names: observer pattern, listener pattern, publisher-subscriber, etc. Look it up if you are interested.



I absolutely agree with item number one above. In fact, that''s why I am phasing it out of my system. It works great though for a small game - like a magic numbers type game - where the required data structures are minimal.

As for number two: I tend to disagree. The main reason I did things this way was because I didn''t want objects to rely on each other''s existance. For example: A CAnimation class must know that the gfx/sound class exists in some way. Either as global variables - in which an assumption is made that the variable names are never changed or the pointer to the gfx/sound class is otherwise fed to the CAnimation class - perhaps on instantiation. Rather than passing pointers to the gfx/sound etc class - I chose this method.

This provided the benefit that any class does not realy on the fact that any other class (for this purpose - engine) exists. In effect the programmer can say, "I don''t know if there is a sound engine, but if there is - Play this sound!"

As I said, it works wonderfully for simpler games. But the additional overhead required and complexity (due to type conversion to void*) make it unwieldly for larger games.

Regards,
Jumpster

Share this post


Link to post
Share on other sites
quote:

As I said, it works wonderfully for simpler games. But the additional overhead required and complexity (due to type conversion to void*) make it unwieldly for larger games.



there is no need to do any void* casting - a clever ''variant'' class could (and should) be used instead. void*''s make me ill. the variant class would use templates heavily so no actual conversions would happen and there would be no speed loss.

Share this post


Link to post
Share on other sites
quote:
Original post by Yorvik

[quote]
As I said, it works wonderfully for simpler games. But the additional overhead required and complexity (due to type conversion to void*) make it unwieldly for larger games.



quote:

there is no need to do any void* casting - a clever 'variant' class could (and should) be used instead. void*'s make me ill. the variant class would use templates heavily so no actual conversions would happen and there would be no speed loss.



I always say, "You learn something new everyday, or else you ain't living!"

Teach me oh wise one... Please provide an example.

Converting a function that takes a void* to a function that takes a variant for I do not know Obie Won...

Regards,
Jumpster

Edited by - Jumpster on February 1, 2001 10:18:22 PM

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!