├── .project
├── src
├── event
│ ├── EventBus.cpp
│ ├── HandlerRegistration.hpp
│ ├── Object.hpp
│ ├── PlayerChatEvent.hpp
│ ├── PlayerMoveEvent.hpp
│ ├── Event.hpp
│ ├── EventHandler.hpp
│ └── EventBus.hpp
├── Player.hpp
└── Main.cpp
├── .cproject
└── README.md
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | EventBus
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder
10 | clean,full,incremental,
11 |
12 |
13 |
14 |
15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
16 | full,incremental,
17 |
18 |
19 |
20 |
21 |
22 | org.eclipse.cdt.core.cnature
23 | org.eclipse.cdt.core.ccnature
24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature
25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/event/EventBus.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #include "EventBus.hpp"
24 |
25 | // Declare the static instance since this can't be done in the header file
26 | EventBus* EventBus::instance = nullptr;
27 |
28 |
--------------------------------------------------------------------------------
/src/event/HandlerRegistration.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef _SRC_EVENT_HANDLER_REGISTRATION_HPP_
24 | #define _SRC_EVENT_HANDLER_REGISTRATION_HPP_
25 |
26 | #include "Object.hpp"
27 |
28 | /**
29 | * \brief Interface that that allows event handlers to be removed from the EventBus
30 | */
31 | class HandlerRegistration : public Object {
32 | public:
33 | virtual ~HandlerRegistration() { }
34 |
35 | virtual void removeHandler() = 0;
36 | };
37 |
38 | #endif /* _SRC_EVENT_HANDLER_REGISTRATION_HPP_ */
39 |
--------------------------------------------------------------------------------
/src/event/Object.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef _SRC_EVENT_OBJECT_HPP_
24 | #define _SRC_EVENT_OBJECT_HPP_
25 |
26 | /**
27 | * \brief Root class of the type hierarchy
28 | *
29 | * All events and event handlers derive from this class
30 | */
31 | class Object {
32 | public:
33 | /**
34 | * \brief Default empty constructor
35 | */
36 | Object() { }
37 |
38 |
39 | /**
40 | * Empty virtual destructor
41 | */
42 | virtual ~Object() { }
43 |
44 |
45 | /**
46 | * Default empty copy constructor
47 | * @param other The instance to copy from
48 | */
49 | Object (const Object& other) { }
50 | };
51 |
52 | #endif /* _SRC_EVENT_OBJECT_HPP_ */
53 |
--------------------------------------------------------------------------------
/src/event/PlayerChatEvent.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef _SRC_EVENT_PLAYER_CHAT_EVENT_HPP_
24 | #define _SRC_EVENT_PLAYER_CHAT_EVENT_HPP_
25 |
26 | #include "Event.hpp"
27 | #include "Player.hpp"
28 |
29 | #include
30 |
31 | class PlayerChatEvent : public Event
32 | {
33 | public:
34 | PlayerChatEvent(Object & sender, Player & player, std::string const & msg) :
35 | Event(sender),
36 | player(player),
37 | msg(msg) {
38 | }
39 |
40 | virtual ~PlayerChatEvent() { }
41 |
42 | Player & getPlayer() {
43 | return player;
44 | }
45 |
46 | std::string const & getMessage() {
47 | return msg;
48 | }
49 |
50 | private:
51 | Player & player;
52 | std::string const & msg;
53 |
54 | };
55 |
56 | #endif /* _SRC_EVENT_PLAYER_CHAT_EVENT_HPP_ */
57 |
--------------------------------------------------------------------------------
/src/Player.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef _SRC_PLAYER_HPP_
24 | #define _SRC_PLAYER_HPP_
25 |
26 | #include "Object.hpp"
27 | //#include "PlayerMoveEvent.hpp"
28 |
29 | #include
30 |
31 | class PlayerMoveEvent;
32 |
33 | /**
34 | * \brief Demo class to showcase some of the features of the EventBus
35 | *
36 | * This is not part of the core functionality and can be modified or deleted as desired
37 | */
38 | class Player : public Object
39 | {
40 | public:
41 | Player(std::string name) :
42 | name(name),
43 | posX(0),
44 | posY(0),
45 | posZ(0)
46 | { }
47 |
48 | virtual ~Player() {
49 |
50 | }
51 |
52 | const std::string & getName() {
53 | return name;
54 | }
55 |
56 | void setPosition(int x, int y, int z) {
57 | posX = x;
58 | posY = y;
59 | posZ = z;
60 | }
61 |
62 | int getX() {
63 | return posX;
64 | }
65 |
66 | int getY() {
67 | return posY;
68 | }
69 |
70 | int getZ() {
71 | return posZ;
72 | }
73 |
74 | private:
75 | std::string name;
76 | int posX;
77 | int posY;
78 | int posZ;
79 |
80 | };
81 |
82 |
83 | #endif /* _SRC_PLAYER_HPP_ */
84 |
--------------------------------------------------------------------------------
/src/event/PlayerMoveEvent.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef _SRC_EVENT_PLAYER_MOVE_EVENT_HPP_
24 | #define _SRC_EVENT_PLAYER_MOVE_EVENT_HPP_
25 |
26 | #include "Event.hpp"
27 | #include "Player.hpp"
28 |
29 | #include
30 |
31 | /**
32 | * \brief Example event class to showcase some of the features of the EventBus
33 | *
34 | * This is not part of the core functionality and can be modified or deleted as desired
35 | */
36 | class PlayerMoveEvent : public Event
37 | {
38 | public:
39 | PlayerMoveEvent(Object & sender, Player & player, int oldX, int oldY, int oldZ) :
40 | Event(sender),
41 | player(player),
42 | oldX(oldX),
43 | oldY(oldY),
44 | oldZ(oldZ) {
45 | }
46 |
47 | virtual ~PlayerMoveEvent() { }
48 |
49 | Player & getPlayer() {
50 | return player;
51 | }
52 |
53 | int getOldX() {
54 | return oldX;
55 | }
56 |
57 | int getOldY() {
58 | return oldY;
59 | }
60 |
61 | int getOldZ() {
62 | return oldZ;
63 | }
64 |
65 | private:
66 | Player & player;
67 |
68 | int oldX;
69 | int oldY;
70 | int oldZ;
71 |
72 | };
73 |
74 | #endif /* _SRC_EVENT_PLAYER_MOVE_EVENT_HPP_ */
75 |
--------------------------------------------------------------------------------
/src/event/Event.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef _SRC_EVENT_EVENT_HPP_
24 | #define _SRC_EVENT_EVENT_HPP_
25 |
26 | #include "Object.hpp"
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | /**
34 | * \brief The base event class, all events inherit from this class
35 | */
36 | class Event : public Object
37 | {
38 | public:
39 | /**
40 | * \brief Default constructor
41 | *
42 | * @param typeIndex The type ID of the inherited class
43 | * @param sender The sender of the event
44 | */
45 | Event(Object & sender) :
46 | sender(sender),
47 | canceled(false) {
48 | }
49 |
50 |
51 | /**
52 | * \brief Empty virtual destructor
53 | */
54 | virtual ~Event() { }
55 |
56 |
57 | /**
58 | * \brief Gets the source object for this event
59 | *
60 | * @return The event sender
61 | */
62 | Object & getSender() {
63 | return sender;
64 | }
65 |
66 |
67 | /**
68 | * \brief Gets whether the event has been canceled
69 | *
70 | * @return true if the event is canceled
71 | */
72 | bool getCanceled() {
73 | return canceled;
74 | }
75 |
76 |
77 | /**
78 | * \brief Sets the canceled status for the event
79 | *
80 | * @param canceled Whether the even is canceled or not
81 | */
82 | void setCanceled(bool canceled) {
83 | this->canceled = canceled;
84 | }
85 |
86 | private:
87 | Object & sender;
88 | bool canceled;
89 |
90 | };
91 |
92 | #endif /* _SRC_EVENT_EVENT_HPP_ */
93 |
--------------------------------------------------------------------------------
/src/event/EventHandler.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef _SRC_EVENT_EVENT_HANDLER_HPP_
24 | #define _SRC_EVENT_EVENT_HANDLER_HPP_
25 |
26 | #include "Object.hpp"
27 |
28 | #include
29 | #include
30 |
31 | // Forward declare the Event class
32 | class Event;
33 |
34 | /**
35 | * \brief Base class of all classes that listen for events
36 | *
37 | * For a class to be an event listener, it needs to inherit from EventHandler
38 | * with the specific event type as the template parameter. A class can inherit from
39 | * multiple EventHandler base classes each using a different template parameter.
40 | */
41 | template
42 | class EventHandler {
43 | public:
44 |
45 | /**
46 | * \brief Default constructor that enforces the template type
47 | */
48 | EventHandler() {
49 | // An error here indicates you're trying to implement EventHandler with a type that is not derived from Event
50 | static_assert(std::is_base_of::value, "EventHandler: T must be a class derived from Event");
51 | }
52 |
53 |
54 | /**
55 | * \brief Empty virtual destructor
56 | */
57 | virtual ~EventHandler() { }
58 |
59 |
60 | /**
61 | * \brief Pure virtual method for implementing the body of the listener
62 | *
63 | * @param The event instance
64 | */
65 | virtual void onEvent(T &) = 0;
66 |
67 |
68 | /**
69 | * \brief Dispatches a generic event to the appropriate listener method
70 | *
71 | * This method is called by the EventBus and dispatches to the correct method by
72 | * dynamic casting the event parameter to the template type for this handler.
73 | *
74 | * @param e The event to dispatch
75 | */
76 | void dispatch(Event & e) {
77 | onEvent(dynamic_cast(e));
78 | }
79 | };
80 |
81 | #endif /* _SRC_EVENT_EVENT_HANDLER_HPP_ */
82 |
--------------------------------------------------------------------------------
/.cproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # C++11 EventBus
2 |
3 | **A lightweight synchronous event framework for C++11**
4 |
5 | ## Overview
6 | Like many other event frameworks, this project allows you to reduce inter-class dependencies and decouple your C++11 code by leveraging synchronous events and event handlers.
7 |
8 | Unlike managed languages such as C# and Java, C++ is statically typed and doesn't support reflection or anonymous delegates making event systems slightly more difficult. This project attempts to create a simple and lightweight event framework that can easily be adapted to any C++11 project. The only requirements are a compiler that supports C++11 and access to the standard C++ libraries. It was inspired by the design of several public event APIs such as in Google's Web Toolkit and those found in popular game modding frameworks.
9 |
10 | The files can be dropped into any existing project as is without any modification or can be easily modified to fit an existing design. One example of a common tweak would be to replace the included Object base class with another base class that is common to the project. The EventBus requires that all events be fired from an Object type which could be replaced by an already existing class in your project.
11 |
12 | The EventBus does perform a few 'unsafe' operations by statically casting to and from void *. This was originally done using the boost::any library to avoid static casting but was changed to void * in the interest of making runtime speed faster and the code more portable. There are many projects that don't include Boost, and the casts are protected through the use of templates which remove the possibility of an incorrect cast.
13 |
14 | ## Source Files
15 | **Core Files**
16 | * */src/event/Event.hpp*
17 | * */src/event/EventBus.cpp*
18 | * */src/event/EventBus.hpp*
19 | * */src/event/EventHandler.hpp*
20 | * */src/event/HandlerRegistration.hpp*
21 | * */src/event/Object.hpp*
22 |
23 | **Example Files**
24 |
25 | These are included for example only and can be deleted when using the framework.
26 | * */src/Main.cpp*
27 | * */src/Player.hpp*
28 | * */src/event/PlayerChatEvent.hpp*
29 | * */src/event/PlayerMoveEvent.hpp*
30 |
31 | ## Usage
32 | ### Firing an Event
33 |
34 | The event bus is designed so that each event type is a unique class that inherits from the *Event* base class. This means that you will need to create the event classes that are specific to your application. There are two example event classes included in the project, *PlayerChatEvent* and *PlayerMoveEvent*. These are two events that you might commonly see in a game development framework. Below you can observe the syntax for creating and firing a player chat event.
35 |
36 | ```c++
37 | Player player1("Player 1"); // Player instance with a name
38 | PlayerChatEvent e(*this, player1, "This is a chat message"); // Create the event object
39 | EventBus::FireEvent(e); // Fire the event
40 | ```
41 |
42 | The PlayerChatEvent takes three parameters: the event sender or source, a reference to the player that is chatting, and then the message text. The act of firing an event is simply to declare an event object and pass it to the static *FireEvent* method. When *FireEvent* is called, it will service all the event handlers for that event type before returning. This synchronous event-based programming is extremely useful in decoupling inter-class dependencies in large code bases.
43 |
44 | ### Creating an Event Handler
45 |
46 | For events to be useful there must be something listening for the events that get fired; that's where the *EventHandler* class comes in. To listen for a particular event, you must have a class that inherits from the *EventHandler* class and implements the virtual method for that event type. Below is a class that will listen for player chat events and print out the chat message with the player name.
47 |
48 | ```c++
49 | class PlayerListener : public EventHandler
50 | {
51 | public:
52 | virtual void onEvent(PlayerChatEvent & e) override {
53 | // Print out the name of the player and the chat message
54 | std::cout << "The player '" << e.getPlayer().getName() << "' said " << e.getMessage();
55 | }
56 | };
57 | ```
58 |
59 | The *PlayerListener* class inherits from *EventHandler* and uses the template parameter of the player chat event. This is the event type that it will listen for. *EventHandler* is a template class and must always be qualified with the type of event that is being targeted. This makes it possible for a single class to listen for multiple events. The class simply needs to inherit from *EventHandler* multiple times, each with a different template parameter.
60 |
61 | All event handler functions must be virtual and called *onEvent* with a single parameter - a reference to the handled event type. The *override* keyword is new in C++11 and tells the compiler that it intends to override an existing virtual function. The compiler will throw an error if the function signature does not match an existing virtual function from an inherited class.
62 |
63 | ### Registering and Unregistering an Event Handler
64 |
65 | The last part is to register the event handler with the event bus using the *AddHandler* method as you can see below.
66 |
67 | ```c++
68 | // Create an instance of PlayerListener and register it with the event bus
69 | PlayerListener pListener;
70 | HandlerRegistration* reg = EventBus::AddHandler(pListener);
71 | ```
72 |
73 | Now the pListener object has been registered and the *onEvent* will be invoked every time a player chat event is fired. The template parameter is again necessary so that the same listener class can be registered as multiple event handlers; this removes any ambiguity as to which base class is being referenced.
74 |
75 | The registered class can also be unregistered by using the returned *HandlerRegistration* object. Once a handler is unregistered, it will no longer recieve events of that type.
76 |
77 | ```c++
78 | // Unregister the listener and delete the registration object
79 | reg->removeHandler();
80 | delete reg;
81 | ```
82 |
83 | The *AddHandler* method also has an optional 2nd parameter that can specify a desired event source. Providing an event source during registration means that event handler will only be invoked when the event is fired from that specified source object.
84 |
85 | ### Creating a Custom Event
86 |
87 | Creating new event classes is easy - just make a new class that inherits from the base *Event* class, implement the constructor and add custom fields and methods. This is what an empty event class looks like without any custom fields or methods.
88 |
89 | ```c++
90 | class MyCustomEvent : public Event
91 | {
92 | public:
93 | MyCustomEvent(Object & sender) :
94 | Event(sender) {
95 | }
96 |
97 | virtual ~MyCustomEvent() { }
98 | };
99 | ```
100 |
101 | The constructor for the *Event* base class requires the event sender as a parameter, so at a minimum your event must have at least one parameter. Beyond this shell class, any custom fields or methods can be added as desired.
102 |
103 |
104 | ## Conclusion
105 |
106 | The above snippets are very top level and the source files, notably Main.cpp, should be examined for a more complete and in-depth example.
107 |
108 | It is quite common to have many event classes in a large application; there are some game frameworks that have hundreds of individual event classes, each in its own file. Although it is easy to make new events, it is useful to consider whether some event types could share the same class if they have similar attributes. For example, a common example is to have an event that simply states that something has happened but doesn't have any data associated with it. In that case, there could be a single status event class with an enumerated list of possible status values. This event could then be used for every type of status flag in the system instead of creating an entirely new event type.
109 |
110 |
111 |
--------------------------------------------------------------------------------
/src/Main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #include "EventHandler.hpp"
24 | #include "EventBus.hpp"
25 | #include "Player.hpp"
26 |
27 | #include "PlayerMoveEvent.hpp"
28 | #include "PlayerChatEvent.hpp"
29 |
30 | #include
31 | #include
32 | #include
33 |
34 |
35 |
36 | /**
37 | * \brief Simple example of an event handler class
38 | *
39 | * This snippet shows how to implement multiple EventHandlers in a single class
40 | */
41 | class PlayerListener : public EventHandler, public EventHandler
42 | {
43 | public:
44 | PlayerListener() { }
45 |
46 | virtual ~PlayerListener() { }
47 |
48 |
49 | /**
50 | * \brief This event handler keeps the player inside a specific border area
51 | *
52 | * @param e The PlayerMoveEvent event
53 | */
54 | virtual void onEvent(PlayerMoveEvent & e) override {
55 |
56 | // Ignore the event if it's already been canceled
57 | if (e.getCanceled()) {
58 | return;
59 | }
60 |
61 | Player & p = e.getPlayer();
62 |
63 | // Cancel the event if the new player position is outside of the border area
64 | if (std::abs(p.getX()) > BORDER_SIZE || std::abs(p.getZ()) > BORDER_SIZE) {
65 | e.setCanceled(true);
66 | printf("Canceled setting player %s position - outside of border\n", p.getName().c_str());
67 | return;
68 | }
69 | }
70 |
71 |
72 | /**
73 | * This event handler prints out a debug message whenever a chat event is fired
74 | *
75 | * @param e The PlayerChatEvent event
76 | */
77 | virtual void onEvent(PlayerChatEvent & e) override {
78 |
79 | // Ignore the event if it's already been canceled
80 | if (e.getCanceled()) {
81 | return;
82 | }
83 |
84 | printf("The player '%s' said: %s\n", e.getPlayer().getName().c_str(), e.getMessage().c_str());
85 | }
86 |
87 | private:
88 | static const int BORDER_SIZE = 500;
89 |
90 | };
91 |
92 |
93 |
94 | /**
95 | * \brief Demo class showing off some functionality of the EventBus
96 | */
97 | class EventBusDemo : public Object
98 | {
99 | public:
100 | EventBusDemo() {
101 | playerMoveReg = nullptr;
102 | playerChatReg = nullptr;
103 | }
104 |
105 | virtual ~EventBusDemo() { }
106 |
107 |
108 | /**
109 | * Demo Function 1
110 | *
111 | * Registers an event listener on player1 and shows how events can be fired and canceled
112 | */
113 | void Demo1() {
114 |
115 | // Two unique player objects
116 | Player player1("Player1");
117 | Player player2("Player2");
118 |
119 | // Declare a local PlayerMoveEvent and use the event bus to fire it
120 | // There are currently no listeners so this won't actually do anything
121 | PlayerMoveEvent e(*this, player1, 0, 0, 0);
122 | EventBus::FireEvent(e);
123 |
124 | // Create the player listener instance
125 | PlayerListener playerListener;
126 |
127 | // Register the player listener to handler PlayerMoveEvent events
128 | // Passing player1 as a second parameter means it will only listen for events from that object
129 | // The return value is a HandlerRegistration pointer that can be used to unregister the event handler
130 | playerMoveReg = EventBus::AddHandler(playerListener, player1);
131 |
132 | // The playerListener gets registered again, but this time as player chat event handler
133 | // The lack of a second parameter means that it will service ALL player chat events,
134 | // regardless of the source
135 | playerChatReg = EventBus::AddHandler(playerListener);
136 |
137 |
138 | int x = 0;
139 |
140 | // This loop will attempt to increase the X position of player one
141 | // by 200 until it reaches 1000 or if the setPosition function fails.
142 |
143 | // The Player.setPosition() method fires a PlayerMoveEvent event internally
144 | //
145 | // The PlayerListener class has an event handler that will cancel the
146 | // PlayerMoveEvent if the X position is greater than 500
147 | while (x <= 1000) {
148 | printf("Changing player 1 X to %d\n", x);
149 |
150 | // This method will fail once X > 500 because of the event handler we registered
151 | if (setPlayerPostionWithEvent(player1, x, 0, 0) == true) {
152 | x += 200;
153 | } else {
154 | printf("Setting player 1 position was canceled\n");
155 | break;
156 | }
157 | }
158 |
159 | x = 0;
160 |
161 | // This loop does the same thing as the loop above, just with player2.
162 | // Since we only registered the PlayerListener to player1, the bounds
163 | // checking will have no effect for this loop
164 | //
165 | // This shows how an event handler will handle data from one source while ignoring others
166 | while (x <= 1000) {
167 | printf("Changing player 2 X to %d\n", x);
168 | if (setPlayerPostionWithEvent(player2, x, 0, 0) == true) {
169 | x += 200;
170 | } else {
171 | printf("Setting player 2 position was canceled\n");
172 | break;
173 | }
174 | }
175 |
176 |
177 | // Here two chat player chat events are created for each player and fired.
178 | // Since the chat listener was registered without a source object, it will service
179 | // all chat events and print both messages
180 | //
181 | // The event handler will print out the player name with the message when the event is fired
182 | PlayerChatEvent chat1(*this, player1, "Hello I am Player 1!");
183 | EventBus::FireEvent(chat1);
184 |
185 | PlayerChatEvent chat2(*this, player2, "Hello I am Player 2!");
186 | EventBus::FireEvent(chat2);
187 |
188 |
189 | // The HandlerRegistration object can be used to unregister the event listener
190 | playerChatReg->removeHandler();
191 |
192 |
193 | // If a chat event is fired again, it will not be serviced since the handler has been unregistered
194 | PlayerChatEvent chat3(*this, player2, "This chat message will not be serviced");
195 | EventBus::FireEvent(chat3);
196 |
197 |
198 | // Clean up
199 | playerMoveReg->removeHandler();
200 | delete playerMoveReg;
201 | delete playerChatReg;
202 | }
203 |
204 | private:
205 | HandlerRegistration* playerMoveReg;
206 | HandlerRegistration* playerChatReg;
207 |
208 |
209 | bool setPlayerPostionWithEvent(Player & player, int x, int y, int z) {
210 |
211 | int savedX = player.getX();
212 | int savedY = player.getY();
213 | int savedZ = player.getZ();
214 |
215 | player.setPosition(x, y, z);
216 |
217 | PlayerMoveEvent e(player, player, savedX, savedY, savedZ);
218 | EventBus::FireEvent(e);
219 |
220 | if (e.getCanceled()) {
221 | player.setPosition(savedX, savedY, savedZ);
222 | return false;
223 | }
224 |
225 | return true;
226 | }
227 |
228 | };
229 |
230 |
231 | int main()
232 | {
233 | printf("* * * EventBus Demo Program * * * \n");
234 |
235 | try
236 | {
237 | EventBusDemo demo;
238 | demo.Demo1();
239 | }
240 | catch (std::runtime_error & e)
241 | {
242 | printf("Runtime exception: %s\n", e.what());
243 | }
244 | }
245 |
246 |
247 |
--------------------------------------------------------------------------------
/src/event/EventBus.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014, Dan Quist
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy
5 | * of this software and associated documentation files (the "Software"), to deal
6 | * in the Software without restriction, including without limitation the rights
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | * copies of the Software, and to permit persons to whom the Software is
9 | * furnished to do so, subject to the following conditions:
10 | *
11 | * The above copyright notice and this permission notice shall be included in
12 | * all copies or substantial portions of the Software.
13 | *
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | * THE SOFTWARE.
21 | */
22 |
23 | #ifndef _SRC_EVENT_EVENT_BUS_HPP_
24 | #define _SRC_EVENT_EVENT_BUS_HPP_
25 |
26 | #include "Object.hpp"
27 | #include "EventHandler.hpp"
28 | #include "Event.hpp"
29 | #include "HandlerRegistration.hpp"
30 |
31 | #include
32 | #include
33 | #include
34 |
35 |
36 | /**
37 | * \brief An Event system that allows decoupling of code through synchronous events
38 | *
39 | */
40 | class EventBus : public Object {
41 | public:
42 | /**
43 | * \brief Default empty constructor
44 | */
45 | EventBus() { }
46 |
47 |
48 | /**
49 | * \brief Empty virtual destructor
50 | */
51 | virtual ~EventBus() { }
52 |
53 |
54 | /**
55 | * \brief Returns the EventBus singleton instance
56 | *
57 | * Creates a new instance of the EventBus if hasn't already been created
58 | *
59 | * @return The singleton instance
60 | */
61 | static EventBus* const GetInstance() {
62 | if (instance == nullptr) {
63 | instance = new EventBus();
64 | }
65 |
66 | return instance;
67 | }
68 |
69 |
70 | /**
71 | * \brief Registers a new event handler to the EventBus with a source specifier
72 | *
73 | * The template parameter is the specific type of event that is being added. Since a class can
74 | * potentially inherit multiple event handlers, the template specifier will remove any ambiguity
75 | * as to which handler pointer is being referenced.
76 | *
77 | * @param handler The event handler class
78 | * @param sender The source sender object
79 | * @return An EventRegistration pointer which can be used to unregister the event handler
80 | */
81 | template
82 | static HandlerRegistration* const AddHandler(EventHandler & handler, Object & sender) {
83 | EventBus* instance = GetInstance();
84 |
85 | // Fetch the list of event pairs unique to this event type
86 | Registrations* registrations = instance->handlers[typeid(T)];
87 |
88 | // Create a new collection instance for this type if it hasn't been created yet
89 | if (registrations == nullptr) {
90 | registrations = new Registrations();
91 | instance->handlers[typeid(T)] = registrations;
92 | }
93 |
94 | // Create a new EventPair instance for this registration.
95 | // This will group the handler, sender, and registration object into the same class
96 | EventRegistration* registration = new EventRegistration(static_cast(&handler), registrations, &sender);
97 |
98 | // Add the registration object to the collection
99 | registrations->push_back(registration);
100 |
101 | return registration;
102 | }
103 |
104 |
105 | /**
106 | * \brief Registers a new event handler to the EventBus with no source specified
107 | *
108 | * @param handler The event handler class
109 | * @return An EventRegistration pointer which can be used to unregister the event handler
110 | */
111 | template
112 | static HandlerRegistration* const AddHandler(EventHandler & handler) {
113 | EventBus* instance = GetInstance();
114 |
115 | // Fetch the list of event pairs unique to this event type
116 | Registrations* registrations = instance->handlers[typeid(T)];
117 |
118 | // Create a new collection instance for this type if it hasn't been created yet
119 | if (registrations == nullptr) {
120 | registrations = new Registrations();
121 | instance->handlers[typeid(T)] = registrations;
122 | }
123 |
124 | // Create a new EventPair instance for this registration.
125 | // This will group the handler, sender, and registration object into the same class
126 | EventRegistration* registration = new EventRegistration(static_cast(&handler), registrations, nullptr);
127 |
128 | // Add the registration object to the collection
129 | registrations->push_back(registration);
130 |
131 | return registration;
132 | }
133 |
134 |
135 | /**
136 | * \brief Fires an event
137 | *
138 | * @param e The event to fire
139 | */
140 | static void FireEvent(Event & e) {
141 | EventBus* instance = GetInstance();
142 |
143 | Registrations* registrations = instance->handlers[typeid(e)];
144 |
145 | // If the registrations list is null, then no handlers have been registered for this event
146 | if (registrations == nullptr) {
147 | return;
148 | }
149 |
150 | // Iterate through all the registered handlers and dispatch to each one if the sender
151 | // matches the source or if the sender is not specified
152 | for (auto & reg : *registrations) {
153 | if ((reg->getSender() == nullptr) || (reg->getSender() == &e.getSender())) {
154 |
155 | // This is where some magic happens. The void * handler is statically cast to an event handler
156 | // of generic type Event and dispatched. The dispatch function will then do a dynamic
157 | // cast to the correct event type so the matching onEvent method can be called
158 | static_cast*>(reg->getHandler())->dispatch(e);
159 | }
160 | }
161 | }
162 |
163 |
164 | private:
165 | // Singleton class instance
166 | static EventBus* instance;
167 |
168 |
169 | /**
170 | * \brief Registration class private to EventBus for registered event handlers
171 | */
172 | class EventRegistration : public HandlerRegistration
173 | {
174 | public:
175 | typedef std::list Registrations;
176 |
177 |
178 | /**
179 | * \brief Represents a registration object for a registered event handler
180 | *
181 | * This object is stored in a collection with other handlers for the event type.
182 | *
183 | * @param handler The event handler
184 | * @param registrations The handler collection for this event type
185 | * @param sender The registered sender object
186 | */
187 | EventRegistration(void * const handler, Registrations * const registrations, Object * const sender ) :
188 | handler(handler),
189 | registrations(registrations),
190 | sender(sender),
191 | registered(true)
192 | { }
193 |
194 |
195 | /**
196 | * \brief Empty virtual destructor
197 | */
198 | virtual ~EventRegistration() { }
199 |
200 |
201 | /**
202 | * \brief Gets the event handler for this registration
203 | *
204 | * @return The event handler
205 | */
206 | void * const getHandler() {
207 | return handler;
208 | }
209 |
210 |
211 | /**
212 | * \brief Gets the sender object for this registration
213 | *
214 | * @return The registered sender object
215 | */
216 | Object* const getSender() {
217 | return sender;
218 | }
219 |
220 |
221 | /**
222 | * \brief Removes an event handler from the registration collection
223 | *
224 | * The event handler will no longer receive events for this event type
225 | */
226 | virtual void removeHandler() {
227 | if (registered) {
228 | registrations->remove(this);
229 | registered = false;
230 | }
231 | }
232 |
233 | private:
234 | void * const handler;
235 | Registrations* const registrations;
236 | Object* const sender;
237 |
238 | bool registered;
239 | };
240 |
241 | typedef std::list Registrations;
242 | typedef std::unordered_map*> TypeMap;
243 |
244 | TypeMap handlers;
245 |
246 | };
247 |
248 | #endif /* _SRC_EVENT_EVENT_BUS_HPP_ */
249 |
--------------------------------------------------------------------------------