Event System Discussion

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Event System Discussion

      Hey All,

      I've been debating with some coworkers how the event system works with different event types (static member HashString that gets compared), and a few things come to mind.

      First, given that the type-implementation appears to duplicate the function of RTTI, has anyone considered just identifying events using RTTI? I assume that it's not really worth the overhead (one int vs the typeid struct).

      Secondly, what about each event having a static list of event listeners? This removes the overhead of searching the map, as each event can simply be dispatched to that class' static list of listeners (referenced directly through that instance of the class). Similarly, listeners could register by doing EventTypeA::AddListener(listener); or something similar. The biggest downsides we came up with for this was that this then requires more identical code between event classes, and as there is no way to subclass a static and have it be unique to that subclass (other than possibly through specializing a template), it would be a little bit messier.

      I'm not saying either of these things are improvements, but they've been fun to debate :)

      Thoughts anyone?

      Cheers,
      RVP

      The post was edited 1 time, last by rickvanprim ().

    • How about this - in the debug build, events and listeners are dynamic, but build up an XML data file that can be read by a runtime system that creates static mappings, and reduces map searches to referring to a constant.

      You could extend the system to allow for dynamic event and listener registration, but those could be "special" events that may be difficult to handle with a static map.

      This gives you the best of both worlds.
      Mr.Mike
      Author, Programmer, Brewer, Patriot
    • I'm currently thinking I'll either use a hashed string implementation, or just a static counter somewhere that assigns IDs, as that would effectively mimic having a global enum, but the IDs would only be meaningful at runtime as they could potentially get initialized in a different order depending on event types being declared external to the engine. Both of those lend well to constexpr whenever that comes out. Hopefully this C++ renaissance the VC++ team has been going on about will have some awesome improvements. :)

      Regarding the listener stuff, I decided that it was best to be able to implement chains of event managers, so the listener collection is still a hash map there. One possible improvement that comes to mind is using function pointers instead of an interface for listeners, as the current implementation does a type look up twice (once to find the list of listeners, and then again inside any listeners that register for more that one type of event). That being said, I'm not all that familiar with doing function pointers to member functions, and then an object instance needs to be passed around, and possibly some other stuff.

      On the subject of actual events, I'm trying to figure out what I like best for manipulating actors in relation to graphics, physics, logic, and presumably other subsystems. So far I'm planning on using the following types:

      Add Actor: anyone who cares notes that there is a new actor, along with any relevant params
      Remove Actor: opposite of Add Actor
      Move Actor: changes the location of the actor, physics ignores this, this event will be triggered by the physics subsystem for any objects connected to it
      Add Force to Actor: means of manipulating the physics object associated with the actor
      Remove Force to Actor: same as above
      Teleport Actor: moves the physics object associated with the actor (which will then be throwing a Move Actor event to trickle down to everything else)

      Note: These are by no means all the event types, just what I'm brainstorming for now. Could very well be some stuff in there about changing other physics properties, applying animations, and whatever else I feel the need for.

      RVP
    • Glad I found this post so I don't start a new thread on the same topic.

      My main question is - why use hash values as unique identifiers instead of the literal strings?

      My assumption is that using a hash value keeps the id's small in the event (no pun intended) that the string identifier is really long.

      My second assumption is that it is easier and safer to send hash values via packets over a network than raw string data.

      Of course I'm not saying that hashing ids is a bad idea, I just don't fully understand the advantages over using literal strings or using an incremental static counter as was suggested in an earlier post.
    • Size isn't as important as speed.

      Strings are O(n) complexity when you compare them, so they are fairly slow (under the covers, it effectively loops through the two strings and compares each character until it finds one that doesn't match). Iterating through a list or tree doing string compares on each element is something you want to avoid.

      Hash maps are usually implemented conceptually as arrays of linked lists, where the hashed value is just the index into that array. This gives you constant-time lookup for that element. The linked lists are there to handle collisions. If you happen to generate the same hash from two different strings, you push the second chunk onto the linked list at the appropriate index. The idea here is that you only have to do the expensive non-hashed string compare on a very small set of data, making it much faster. For an event system where the data needs to be accessed many times each frame, this can be very important.

      That's the basic idea, anyway.

      -Rez
    • Ah good ol' speed. Something that should never be even slightly overlooked in a game. I remember playing the classic Decent series in a screen shrunk down to the size of a cell phone to get a playable framerate. That was my only option on my 50Mhz 486DX2. Meanwhile my friend had a pentium 90 machine and played fullscreen with a nice smooth framerate. Needless to say I wasn't much competition for him in deathmatch.

      A few years later we battled each other in Descent II, only this time I had a machine that could run the game flawlessly. Oh how the tables turned, much to my friend's dismay. :)

      Anyway, thanks for answering my question rez!