Event Channel Design Documentation

From FIFE development wiki
Jump to: navigation, search

This article is part of design documentation. Design 32.png

Design documentation describes how software is implemented or is about to be implemented. It focuses on system structure (e.g. dependencies), module interactions and relevant algorithms. Concepts described in these articles should form the terminology that is used when discussing about the software that forms FIFE.

This article is outdated and needs to be reviewed! Outdated.png

The content of this article is outdated and should be treated as such. We cannot guarantee the accuracy of the information presented here.


Introduction

Event channel distributes different kinds of events to other engine modules. Scripts can also subscribe most of the events defined by the event channel. The diagram below illustrates the most important classes and their relationships.


Structure of the event channel


Event manager is the hub of the event channel. It takes care of managing the client subscriptions and related event dispatching. EventManager polls SDL for events and converts them to appropriate event classes. Based on subscription types, events are delivered to event channel clients. E.g. in case client B is interested receiving key events, it:

  • inherits itself from KeyListener
  • Register itself to KeyController
  • receives KeyEvents via KeyListener interface

About interfaces

Event channel uses interfaces to hide implementation from clients; e.g. using plain KeyController interface it is guaranteed that mouse or widget related details are not visible to then client (thus improving encapsulation). In case client would use EventManager interface directly it would also gain visibility to event types that are not needed in that module. The same principle works also to other direction; event manager does not know anything about its client, since all communication happens through the ...Listener and EventSource interfaces.

Most important interface types are:

  • Listeners (e.g. KeyListener, MouseListener)
    Manager pushes event to clients using these interfaces
  • Controllers (e.g. KeyController)
    Clients can subscribe themselves to corresponding events using these interfaces
  • Dispatchers (e.g. CommandDispatcher)
    Clients can send events to other clients using this interface
    In the picture client A is able to send commands to client B, if:
    • client B inherits CommandListener
    • client B subscribes to listen commands via CommandController
    • Client A inherits from EventSource
    • Client A sends a command via CommandDispatcher (and sets itself as the eventsource of sent command)

Interactions

Dispatching raw SDL_Events

In some cases other modules may require raw SDL events. This is the case e.g. with gui (which passes events to guichan). In those cases, clients should subscribe themselves as SDLEventListeners. After subscription, message dispatching happens in the following way:

EventManager: get event from SDL
EventManager: convert event to fife event
EventManager: dispatch fife event to appropriate listeners
EventManager: dispatch raw event to SDLEventListeners

Note that other modules might react to received SDL_events in such way, that they send new events to other modules via event channel

Dispatching KeyEvents

After receiving SDL event and converting it to corresponding engine event, the following happens:

EventManager: for each KeyEventListener:
  EventManager: dispatch event to listener
    KeyEventListener: examine the received event (e.g. capslock, shift, key value)
    KeyEventListener: in case criteria is met, react to keyevent (e.g. move character)

Events can be consumed by the listeners, so that dispatching of consumed event is stopped. The problem with consuming is the concept of focus; in some cases it makes sense to consume the event (e.g. when typing text to text area, arrow keys should move only the caret, not the player agent), while in others not (e.g. ESC key should quit the game in every case). By default events can be consumed by clients. This behavior can be adjusted for each key from event manager.

Dispatching WidgetEvents

Widget events are converted from gui events that engine happens to be using (atm that means guichan). The key difference here is that gui does the actual dispatching in the following way:

EventManager: for SDL_Event that is a key event
  EventManager: for each KeyListener:
    EventManager: dispatch KeyEvent:
      Gui: if there is active focus handler (*)
        Gui: consume the key event
  EventManager: for each SDLEventListener:
    EventManager: dispatch event to listener
      Gui: receive SDLEvent
      Gui: push event to guichan
        Guichan: create appropriate Guichan event
        Guichan: send event to listeners
          Gui: receive event from guichan, convert to WidgetEvent
          Gui: dispatch widget event to KeyEventController
            EventManager: receive widget event, for each WidgetEventListener
              WidgetEventListener: receive widget event, react to that

Mouse events are converted to widget events in similar manner, the key difference however is in the Gui when MouseEvent is received ((*)-marking). In that case Gui consumes mouse event in case there is visible widget underneath the click point.

Dispatching Commands

Clients can dispatch commands to other clients via CommandDispatcher interface:

client x: create Command
client x: dispatch command via CommandDispatcher
  EventManager: dispatch command to CommandListeners
    client y: receive command