--- /dev/null
+#ifndef MSP_GAME_EVENTSOURCE_H_
+#define MSP_GAME_EVENTSOURCE_H_
+
+#include "eventbus.h"
+#include "eventobserver.h"
+
+namespace Msp::Game {
+
+class EventObserver;
+
+class EventSourceBase
+{
+protected:
+ EventBus &bus;
+
+public:
+ EventSourceBase(EventBus &b): bus(b) { }
+
+ virtual void remove_observer(EventObserver &) = 0;
+};
+
+
+template<typename... E>
+class EventSource: public EventSourceBase, private EventDispatcher<E>...
+{
+public:
+ EventSource(EventBus &b): EventSourceBase(b) { }
+ ~EventSource() { (cancel_observation<E>(), ...); }
+
+ template<typename T>
+ void add_observer(EventObserver &obs, std::function<void(const T &)> cb)
+ { static_cast<EventDispatcher<T> &>(*this).add_observer(obs, std::move(cb)); }
+
+ void remove_observer(EventObserver &obs) override
+ { (static_cast<EventDispatcher<E> &>(*this).remove_observer(&obs), ...); }
+
+private:
+ template<typename T>
+ void cancel_observation();
+
+public:
+ template<typename T, typename... Args>
+ void emit(Args &&...) const;
+};
+
+
+template<typename... E>
+template<typename T, typename... Args>
+inline void EventSource<E...>::emit(Args &&... args) const
+{
+ T event(std::forward<Args>(args)...);
+ static_cast<const EventDispatcher<T> &>(*this).dispatch(event);
+ bus.dispatch(event);
+}
+
+template<typename... E>
+template<typename T>
+inline void EventSource<E...>::cancel_observation()
+{
+ for(const auto &h: static_cast<EventDispatcher<T> &>(*this).handlers)
+ h.observer->remove_source(*this);
+}
+
+} // namespace Msp::Game
+
+#endif