Messaging System

Started by
15 comments, last by SeanHowe 23 years, 2 months ago
class CAvatar: public CWorldObserver
{
}

Obviously needs a lot of work, but I was thinking that Avatar would ''emit'' events into the world, and the world would decide what other avatars could possibly notice the event and then send notification of the event via the WorldObserver.

The instance class gets first crack at handling the event, and then it''s passed up the derived "Chain of Command" until it''s either handled or discarded.

Magmai Kai Holmlor
- The disgruntled & disillusioned
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Advertisement
quote:
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...


there was a thread about this kind of thing a few weeks back:

http://www.gamedev.net/community/forums/topic.asp?topic_id=36449

scroll down to wilkas big reply.
quote:
a clever ''variant'' class could (and should) be used instead

I admit, variant is a bit better then void* but you still are not guaranteed that you handler receives correct data:
  //// code in the message source //// store a long in the variantVARAINT var;var.vt = VT_I4;var.lVal = 42;SendCommand(MY_MESSAGE, var);//// code in the message handler//OnCommand(message, VARIANT param){  if(MY_MESSAGE== message)  {     // handler expects a BSTR     DoSomething(param.bstrVal);  }}  

There’s an obvious bug in the code above but it would compile just fine because VARIANT hides exact type from the compiler. Yeah, you can check it at runtime:
  // handler expects a BSTRif(VT_BSTR != var.vt){  // handle error}DoSomething(param.bstrVal);  

But you still have a runtime error and you need to figure out what to do with it. I’d rather write code that _can’t_ have this type of errors:
  void DoSomething(BSTR);long some_long = 42;DoSomething(some_long);  

This won’t even compile which is exactly the point – you catch and fix the bug at compile time.

quote:
the variant class would use templates heavily so no actual conversions would happen and there would be no speed loss.

Templates got nothing to do with it. Wilka’s example that you are quoting relies on having a base class, template just provides generic implementations for derived classes. So, you will have a base class pointer that you will need to downcast to the correct type – that’s almost as bad as using void*.

It does not matter which mechanism you use – you are still disabling type checking somehow. That’s the only way to code a message dispatcher that accepts any type of arguments.

quote:
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!"

Interesting... The way I see it sound system is accessed from so many places that it needs to be global in some sense. How you do that – message dispatcher or global variables (ugh!) or singletons – does not really matter (although I do prefer singletons). Alternatively, you could pass a sound system reference to every object that needs to play a sound but I think it clutters interfaces.
What I was trying to say is that any object hooked up to the central message dispatcher becomes globally accessible. It’s ok for something like a sound system, but exposing all your game entities (for example) is a debugging nightmare waiting to happen. I’d rather see them safely hidden inside a CGame class or something like that.

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.

Yep. Conversion is not the only issue. Message dispatcher is just too convenient. On a large project it can lead to “Deadline is tomorrow and I have no time for proper design so I just gonna send a message from here and handle it there” mindset. Design goes down the drain. End result - a system with several hundreds objects, a hundred or so messages, and not one person who knows what’s going on.

I’m not saying that message dispatchers are totally evil. I’m just saying they have certain drawbacks and usually you can implement exact same functionality in a different (better, IMHO) way.
I know I started this to get input from other people, but let me just put something in for you guys.
If you want to pass arguments, since you''re not going to get typechecking any way you go about it, why not just use va_list''s? They''re much cleaner for the programmer than filling a structure for the parameters and then passing a pointer to it.

(For those of you who don''t know, a va_list is what functions like printf use to acheive multiple parameters like that)
quote:Original post by SeanHowe

I know I started this to get input from other people, but let me just put something in for you guys.
If you want to pass arguments, since you''re not going to get typechecking any way you go about it, why not just use va_list''s? They''re much cleaner for the programmer than filling a structure for the parameters and then passing a pointer to it.

(For those of you who don''t know, a va_list is what functions like printf use to acheive multiple parameters like that)

How would you pass those from the dispatcher to individual handlers?

quote:
Interesting... The way I see it sound system is accessed from so many places that it needs to be global in some sense. How you do that – message dispatcher or global variables (ugh!) or singletons – does not really matter (although I do prefer singletons). Alternatively, you could pass a sound system reference to every object that needs to play a sound but I think it clutters interfaces.


I use the messaging system!

If I need a particular value from the Graphics Engine, say "PixelDepth" I simply send a message to it as such:

SendEngineMessage(itGRAPHICS, WF_PIXELDEPTH, NULL, &pixels);

and I get the appropriate value.

Now, because it''s going through the messaging system, by the time &pixels gets to the Graphics Engine, it''s a (void*) instead of int.

That''s where the problems with (void*) come into play - as you all have pointed out - typechecking!

I have to assume that if (returns != NULL) then it must be an int - which I agree is bad voodoo but it''s the only way to achieve my goals of the system.

and so the code looks like so:

CGRAPHICS::GetPixel(void* params, void* returns){  if (returns != NULL)  {    int* temp = (int*) returns; // Alias the return value...    (*returns) = PixelDepth;    // Update it''s value...  }} 


Regards,
Jumpster

Regards,JumpsterSemper Fi
Just send the handler the va_list that results from the ... parameters. It can then extract the variables it wants from it.

This topic is closed to new replies.

Advertisement