SHADE_Y3/SHADE_Engine/src/Events/SHEventManager.hpp

157 lines
5.4 KiB
C++

/******************************************************************************
* \file SHEventManager.hpp
* \author Loh Xiao Qi
* \brief Class declaration for event manager.
*
* \copyright Copyright (c) 2022 Digipen Institute of Technology. Reproduction
* or disclosure of this file or its contents without the prior written consent
* of Digipen Institute of Technology is prohibited.
******************************************************************************/
#pragma once
#include "SHpch.h"
#include "SHEvent.h"
#include "SHEventReceiver.h"
#include "SH_API.h"
/******************************************************************************
INSTRUCTIONS FOR USE:
On broadcaster side:
1. Create a struct/class to contain the data that you would need to send
in the event.
2. Create unique event identifier in SHEventDefines.h, follow the example
provided.
3. When ready to send the event, call
SHEventManager::BroadcastEvent<ExampleClass>(exampleClass, EVENT_IDENTIFIER);
NOTE: If your custom struct to contain data requires a deep copy, please
overload the assignment operator accordingly. It is fine to send
a single object of a basic type such as int/float.
Headers required: SHEventManager.hpp
On Receiver side:
1. Create a function with the signature:
SHEventHandle FunctionName(SHEventPtr);
2. In the init function of the class, copy the below in and replace the
necessary:
std::shared_ptr<SHEventReceiverSpec<ReceiverClass>> thisReceiver{
std::make_shared<SHEventReceiverSpec<ReceiverClass>>(this, &ReceiverClass::ReceiveFunction)
};
ReceiverPtr receiver = std::dynamic_pointer_cast<SHEventReceiver>(thisReceiver);
SHEventManager::SubscribeTo(EVENT_IDENTIFIER, receiver);
ReceiverClass is the class that the receiver is in. E.g., SHPhysicsSystem
3. Note: The EventIdentifier should match all that is defined in
SHEventDefines.h so check there. When the receiver catches the event, it
needs to know the struct that the broadcaster is using to cast the event
ptr as such:
reinterpret_cast<std::shared_ptr<SHEventSpec<CustomClass>>>(event)
4. Inside the new ptr should be a shared pointer of const CustomClass type.
Headers required: SHEventManager.hpp, SHEventReceiver.h
If you have any questions/suggestions for improvement lmk.
******************************************************************************/
namespace SHADE
{
//using ResponseFunction = std::function<SHEventHandle(SHEventPtr)>;
using ReceiverPtr = std::shared_ptr<SHEventReceiver>;
using ResponseVec = std::vector<ReceiverPtr>;
using EventManagerListener = std::function<void(SHEvent)>;
class SH_API SHEventManager
{
private:
// Registry for broadcasters and subscribers
inline static std::unordered_map<SHEventIdentifier, ResponseVec> packageReceiverRegistry;
inline static SHEventHandle handleCounter {0};
/****************************************************************************
* \param ListenerConstPtr - Const pointer to listener that sent event.
* \param EventType - Event data
* \brief Broadcast event to all receivers that are subscribed to this
* listener.
****************************************************************************/
static void Broadcast(SHEventPtr event)
{
ResponseVec& receivers{ packageReceiverRegistry[event->type] };
for (auto& receiver : receivers)
{
receiver->Receive(event);
}
}
/****************************************************************************
* \param ReceiverPtr - Pointer to receiver
* \param ListenerConstPtr - Const pointer to listener that receiver is
* subscribing to.
* \brief Registers receiver as a subscriber to listener in the registry.
****************************************************************************/
static void RegisterReceiverToType(SHEventIdentifier pkgType, ReceiverPtr receiver)
{
if (packageReceiverRegistry.find(pkgType) == packageReceiverRegistry.end())
{
packageReceiverRegistry.emplace(pkgType, std::vector{ receiver });
}
else
{
packageReceiverRegistry[pkgType].emplace_back(receiver);
}
}
public:
/****************************************************************************
* \param ListenerConstPtr - Const pointer to listener that sent event.
* \param EventType - Templated type for every type of event
* \brief Receives event from the listeners.
****************************************************************************/
static void CatchEvent(SHEventPtr event)
{
// Do something with the event
Broadcast(event);
}
/****************************************************************************
* \param ResponseFunction - function pointer from receiver to be passed
* into event manager to be called when events are broadcasted.
* \param SHPackageType - package type that corresponding subscriber is
* subscribing to.
* \brief Links a function pointer from a subscriber to a particular
* package type
****************************************************************************/
static void SubscribeTo(SHEventIdentifier pkgType, ReceiverPtr receiver)
{
RegisterReceiverToType(pkgType, receiver);
}
template<typename T>
static void BroadcastEvent(T data, SHEventIdentifier eventType)
{
std::shared_ptr<const T> ptr = std::make_shared<T>(data);
CatchEvent(
std::make_shared<SHEventSpec<T>>(eventType, handleCounter++, ptr)
);
}
};
}