API Addition & Breaking Change, Request for Comments...

Clay

06-12-2005 22:43:54

I'm planning on reimplementing the Ogre event system and I would like some input on the plan. Right now there are multiple Director classes which must be subclassed to add callback functionality to ogre. These include the MouseMotionListener, MouseListener, KeyListener, and FrameListener (are there any I am missing here?).

My idea is to mark all of these director interfaces as depreciated and implement a more pythonic interface for all of this. To do this there will be a new class called "CallbackManager" (any suggestions for a better name?) which allows you to register any Python callable object (such as a member function of a class) to handle the event. For example, instead of inheriting from FrameListener, this would be the new code:

def onFrameStarted(evt):
return True

class MyEventHandler:
def __init__(self):
cm = CallbackManager.getSingleton()

cm.addFrameStartedListener(onFrameStarted)
cm.addKeyUpListener(self.onKeyUp)
cm.addMouseMoveListener(self.onMouseMove)

def onKeyUp(self, evt):
pass

def onMouseMove(self, evt):
pass


I also plan to add priority to each of these functions to allow you to determine which order things are called in:
cm.addFrameStartedListener(self.firstFrameStarted, 1)
cm.addFrameStartedListener(self.secondFrameStarted, 2)

This garuntees that firstFrameStarted is called before secondFrameStarted. You can leave off the priority and it is assigned a default priority of something to be determined.

Why the changes?
  1. First of all this cleans up a lot of the code that uses PyOgre. Subclassing/redefining is not generally the "pythonic" way to do it. Allowing an arbitrary function to be used allows us to use any python callable which has the correct parameters/return values. This could be a class's member function or even just a stand-alone function.[/*:m]
  2. The Ogre API does not handle priority on events. This allows us to ensure listeners are called in the proper order when it is needed. This comes up often and the ogre developers have said "if this is the case, then create your own listeners and add priority that way", which is what we are doing...but in C++ code which leads us to... [/*:m]
  3. This method of handling frame events should be much faster than the current swig director system. This is because only registered events get callbacks and you don't have to deal with the wrapper-generated-overhead. Also since the priority is handled in C++ land (and only when you add/remove new event handlers...which is generally only done rarely) you will not experiance any slowdown associated with priority handling. Finally, since I will only be registering the class as a callback handler if events are actually registered for them, there will not be needless callbacks in C++ land either.[/*:m]
  4. This also allows us to fix some of the broken API with Ogre's event system, such as MouseClicked not working and removing once-and-forall the unneeded methods for some of the MouseMotionListener interface which does not get used.[/*:m][/list:u]

    Overall I think this will make the library much more stable and useable. However I would like to remove the directors that this replaces altogether. This would be a huge interface breaking change, and would not be fully implemented until at least Dagon (1.1.0). That is, the class will be added, but the director classes FrameListener, KeyListener, etc. Would be marked as depreciated but not actually removed until Dagon's release.

    If there are any questions, comments, or concerns about this I'm happy to discuss it now while I'm still in the planning phase.

fog

07-12-2005 09:53:57

I am all for it. Just use the warning framework to spit out annoying message to users still using the old interface and to make sure they know the listeners will go away in the future.

griminventions

10-12-2005 07:02:20

Just to toss something else out there, I've used Simon Wittber's Eventnet, and it solves the problem elegantly by using generators and decorators (ie, mark a function as a subscriber to an event with a decorator--very easy as well as self documenting). I'm not sure how pertinent this will be to your work but it might be useful to have a look at it. There's not much code, so it shouldn't take up a lot of your time.

http://lgt.berlios.de/#eventnet

Good luck with this. Input is such a critical facility. It's very important to get it implemented well.

willism

10-12-2005 18:34:12

I like it. In fact, I was toying around with a similar idea of writing a callback-based event handler for my project a while ago, instead of implementing listeners. I think that this would significantly reduce some of the bloat in my current input handling code.

Clay

10-12-2005 19:19:38

Very interesting stuff griminventions. The only problem with something like that is it does not provide a mechanism for unregistering listeners, or delay-registering listeners. (Please correct me if I missed something here, I did not read all of the documentation, just what was on that page.)

In many game applications you need to register/unregister events while the application is running, and implementing them as decorators does not allow for that.

griminventions

11-12-2005 22:32:53

Actually it's as simple as:
eventnet.dispatcher.subscribe( function, eventName )
So you can mix the two methods for defining subscribers. And of course you can easily unsubscribe as well, using the dispatcher. Hope that gives you some ideas.

Clay

11-12-2005 22:52:41

Does anyone have any preference as to whether I use this system:

eventSystem.addFrameStartedListener(function)
eventSystem.addMouseMoveListener(function2)


or this:

eventSystem.bind(function, ogre.EVT_FrameStarted)
eventSystem.bind(function2, ogre.EVT_MouseMove)


I have written #1, but I think I like #2 better.

I should have something to play with next weekend. Finals week is bad. =/

griminventions

12-12-2005 14:47:10

#2 seems like it would be less work for you since #1 would require a new function for each event type. All else being equal, go for #2 and save yourself some effort. :)