Gamedev Framework (gf)  0.3.0
A C++11 framework for 2D games
MessageManager.h
1 /*
2  * Gamedev Framework (gf)
3  * Copyright (C) 2016 Julien Bernard
4  *
5  * This software is provided 'as-is', without any express or implied
6  * warranty. In no event will the authors be held liable for any damages
7  * arising from the use of this software.
8  *
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  *
13  * 1. The origin of this software must not be misrepresented; you must not
14  * claim that you wrote the original software. If you use this software
15  * in a product, an acknowledgment in the product documentation would be
16  * appreciated but is not required.
17  * 2. Altered source versions must be plainly marked as such, and must not be
18  * misrepresented as being the original software.
19  * 3. This notice may not be removed or altered from any source distribution.
20  */
21 #ifndef GF_MESSAGE_MANAGER_H
22 #define GF_MESSAGE_MANAGER_H
23 
24 #include <cstdint>
25 #include <functional>
26 #include <initializer_list>
27 #include <map>
28 #include <type_traits>
29 #include <vector>
30 
31 #include "Message.h"
32 #include "Portability.h"
33 
34 namespace gf {
35 #ifndef DOXYGEN_SHOULD_SKIP_THIS
36 inline namespace v1 {
37 #endif
38 
39  /**
40  * @ingroup game
41  * @brief An identifier for a message handler
42  *
43  * @sa gf::MessageHandler
44  */
45  using MessageHandlerId = uint64_t;
46 
47  /**
48  * @ingroup game
49  * @brief A message manager
50  *
51  * A message manager is responsible for passing messages synchronously
52  * between game entities. It relies on a variant of the
53  * [observer pattern](https://en.wikipedia.org/wiki/Observer_pattern).
54  * Some entities send messages (subclasses of gf::Message identified by
55  * their unique message type) to the message manager while some other
56  * entities listen to messages of a defined type through a message
57  * handler (gf::MessageHandler). As a consequence, there is very low
58  * [coupling](https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29)
59  * between entities.
60  *
61  * Generally, you only need one message manager in a game. It is a good
62  * candidate for being a singleton (thanks to gf::Singleton).
63  *
64  * ~~~{.cc}
65  * gf::Singleton<gf::MessageManager> gMessageManager;
66  *
67  * int main() {
68  * gf::SingletonStorage<gf::MessageManager> storageForMessageManager(gMessageManager);
69  *
70  * gMessageManager().sendMessage(&foo);
71  * }
72  * ~~~
73  *
74  * @sa gf::Message, gf::MessageHandler, gf::Id
75  */
77  public:
78  /**
79  * @brief Constructor
80  */
82 
83  /**
84  * @name Registering an handler
85  * @{
86  */
87 
88  /**
89  * @brief Register a message handler for a type of message
90  *
91  * ~~~{.cc}
92  * struct Foo : public gf::Message {
93  * static const gf::Id type = "Foo"_id;
94  * // other fields
95  * };
96  *
97  * gf::MessageHandler handler = ...;
98  *
99  * gf::MessageManager messages;
100  * messages.registerHandler(Foo::type, handler);
101  * ~~~
102  *
103  * @param type The type of message
104  * @param handler The message handler
105  * @return A handler id
106  */
107  MessageHandlerId registerHandler(Id type, MessageHandler handler);
108 
109  /**
110  * @brief Register a message handler for a type of message
111  *
112  * ~~~{.cc}
113  * struct Foo : public gf::Message {
114  * static const gf::Id type = "Foo"_id;
115  * // other fields
116  * };
117  *
118  * gf::MessageHandler handler = ...;
119  *
120  * gf::MessageManager messages;
121  * messages.registerHandler<Foo>(handler);
122  * ~~~
123  *
124  * @param handler The message handler
125  * @return A handler id
126  */
127  template<typename E>
128  MessageHandlerId registerHandler(MessageHandler handler) {
129  static_assert(std::is_base_of<Message, E>::value, "E must be an Message");
130  static_assert(E::type != InvalidId, "E must define its type");
131  return registerHandler(E::type, handler);
132  }
133 
134  /**
135  * @brief Register a message handler for a type of message
136  *
137  * ~~~{.cc}
138  * struct Foo : public gf::Message {
139  * static const gf::Id type = "Foo"_id;
140  * // other fields
141  * };
142  *
143  * class Bar {
144  * gf::MessageStatus onFoo(gf::Id type, gf::Message *msg) {
145  * // do something useful
146  * return gf::MessageStatus::Keep;
147  * }
148  * };
149  *
150  * Bar bar;
151  *
152  * gf::MessageManager messages;
153  * messages.registerHandler(Foo::type, &Bar::onFoo, &bar);
154  * ~~~
155  *
156  * @param type The type of message
157  * @param pm A pointer to member function that represents the handler
158  * @param obj The destination object that receives the message
159  * @return A handler id
160  */
161  template<typename R, typename T>
162  MessageHandlerId registerHandler(Id type, R T::*pm, T *obj) {
163  return registerHandler(type, std::bind(pm, obj, std::placeholders::_1, std::placeholders::_2));
164  }
165 
166  /**
167  * @brief Register a message handler for a type of message
168  *
169  * ~~~{.cc}
170  * struct Foo : public gf::Message {
171  * static const gf::Id type = "Foo"_id;
172  * // other fields
173  * };
174  *
175  * class Bar {
176  * gf::MessageStatus onFoo(gf::Id type, gf::Message *msg) {
177  * // do something useful
178  * return gf::MessageStatus::Keep;
179  * }
180  * };
181  *
182  * Bar bar;
183  *
184  * gf::MessageManager messages;
185  * messages.registerHandler<Foo>(&Bar::onFoo, &bar);
186  * ~~~
187  *
188  * @param pm A pointer to member function that represents the handler
189  * @param obj The destination object that receives the message
190  * @return A handler id
191  */
192  template<typename E, typename R, typename T>
193  MessageHandlerId registerHandler(R T::*pm, T *obj) {
194  static_assert(std::is_base_of<Message, E>::value, "E must be an Message");
195  static_assert(E::type != InvalidId, "E must define its type");
196  return registerHandler(E::type, std::bind(pm, obj, std::placeholders::_1, std::placeholders::_2));
197  }
198 
199  /** @} */
200 
201  /**
202  * @name Removing an handler
203  * @{
204  */
205 
206  /**
207  * @brief Remove a handler
208  *
209  * @param id The handler id
210  */
211  void removeHandler(MessageHandlerId id);
212 
213  /**
214  * @brief Remove a list of handlers
215  *
216  * @param ids The list of handler ids
217  */
218  void removeHandlers(std::initializer_list<MessageHandlerId> ids) {
219  for (auto id : ids) {
220  removeHandler(id);
221  }
222  }
223 
224  /** @} */
225 
226  /**
227  * @name Sending a message
228  * @{
229  */
230 
231  /**
232  * @brief Send a message
233  *
234  * The message is sent synchronously i.e. immediately when calling the
235  * function. A consequence is that the memory for the message can be
236  * allocated on the stack because it only has to live during the function
237  * call.
238  *
239  * ~~~{.cc}
240  * struct Foo : public gf::Message {
241  * static const gf::Id type = "Foo"_id;
242  * // other fields
243  * };
244  *
245  * Foo foo;
246  *
247  * gf::MessageManager messages;
248  * messages.sendMessage(Foo::type, &foo);
249  * ~~~
250  *
251  * @param type The message type
252  * @param message A pointer to the message
253  */
254  void sendMessage(Id type, Message *message);
255 
256  /**
257  * @brief Send a message
258  *
259  * The message is sent synchronously i.e. immediately when calling the
260  * function. A consequence is that the memory for the message can be
261  * allocated on the stack because it only has to live during the function
262  * call.
263  *
264  * ~~~{.cc}
265  * struct Foo : public gf::Message {
266  * static const gf::Id type = "Foo"_id;
267  * // other fields
268  * };
269  *
270  * Foo foo;
271  *
272  * gf::MessageManager messages;
273  * messages.sendMessage(&foo);
274  * ~~~
275  *
276  * @param message A pointer to the message
277  */
278  template<typename E>
279  void sendMessage(E *message) {
280  static_assert(std::is_base_of<Message, E>::value, "E must be an Message");
281  static_assert(E::type != InvalidId, "E must define its type");
282  sendMessage(E::type, message);
283  }
284 
285  /** @} */
286 
287  private:
288  struct Handler {
289  MessageHandlerId id;
290  MessageHandler handler;
291  };
292 
293  MessageHandlerId m_currentId;
294  std::map<Id, std::vector<Handler>> m_handlers;
295  };
296 
297 #ifndef DOXYGEN_SHOULD_SKIP_THIS
298 }
299 #endif
300 }
301 
302 #endif // GF_MESSAGE_MANAGER_H
MessageHandlerId registerHandler(MessageHandler handler)
Register a message handler for a type of message.
Definition: MessageManager.h:128
void sendMessage(E *message)
Send a message.
Definition: MessageManager.h:279
friend class RenderTarget
Definition: Shader.h:387
A message manager.
Definition: MessageManager.h:76
MessageHandlerId registerHandler(R T::*pm, T *obj)
Register a message handler for a type of message.
Definition: MessageManager.h:193
MessageHandlerId registerHandler(Id type, MessageHandler handler)
Register a message handler for a type of message.
Definition: Action.h:34
MessageHandlerId registerHandler(Id type, R T::*pm, T *obj)
Register a message handler for a type of message.
Definition: MessageManager.h:162
The base class for all messages.
Definition: Message.h:53
MessageManager()
Constructor.
void removeHandlers(std::initializer_list< MessageHandlerId > ids)
Remove a list of handlers.
Definition: MessageManager.h:218
#define GF_API
Definition: Portability.h:35
void removeHandler(MessageHandlerId id)
Remove a handler.
void sendMessage(Id type, Message *message)
Send a message.