Merge pull request #25 from SHADE-DP/SP3-18-Events

SP3-18 SP3-108 Event/Messaging System

Ported over Events Manager from 200
Removed singleton design pattern
Removed event package design
Implemented event dynamic data

Instructions to use are in SHEventManager.h
This commit is contained in:
XiaoQiDigipen 2022-09-16 01:33:47 +08:00 committed by GitHub
commit cf3f74e47d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 317 additions and 1 deletions

View File

@ -0,0 +1,28 @@
/************************************************************************************//*!
\file SHCommonTypes.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 8, 2022
\brief Contains the definitions of type alias for commonly used units for
clarity and convenience.
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
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/***********************************************************************************/
/*!
\brief
Type used to mark a value that is supposed to represent a size in bytes.
*/
/***********************************************************************************/
using Byte = size_t;
}

View File

@ -0,0 +1,22 @@
/******************************************************************************
* \file SHEvent.h
* \author Loh Xiao Qi
* \brief Event class declaration
*
* \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 "SHEventDefines.h"
namespace SHADE
{
struct SHEvent
{
SHEventIdentifier type;
SHEventDataPtr dataPtr;
SHEventHandle handle;
};
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "SHpch.h"
typedef uint32_t SHEventIdentifier;
typedef uint32_t SHEventHandle;
typedef void* SHEventDataPtr;
//Add your event identifiers here:
constexpr SHEventIdentifier SH_EXAMPLE_EVENT{0};

View File

@ -0,0 +1,107 @@
/******************************************************************************
* \file SHEventManager.cpp
* \author Loh Xiao Qi
* \brief Function Implmentations for SHEventManager
*
* \copyright Copyright (c) 2021 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
******************************************************************************/
#include "SHpch.h"
#include "SHEventManager.h"
namespace SHADE
{
std::unordered_map<SHEventIdentifier, ResponseVec> SHEventManager::packageReceiverRegistry;
std::unordered_map<SHEventHandle, SHEventDataPtr> SHEventManager::dataEventMap;
SHEventHandle SHEventManager::handleCounter{ 0 };
/****************************************************************************
* \param ListenerConstPtr - Const pointer to listener that sent event.
* \param EventType - Templated type for every type of event
* \brief Receives event from the listeners.
****************************************************************************/
void SHEventManager::CatchEvent(SHEvent 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 SHEventIdentifier - package type that corresponding subscriber is
* subscribing to.
* \brief Links a function pointer from a subscriber to a particular
* package type
****************************************************************************/
void SHEventManager::SubscribeTo(SHEventIdentifier pkgType, ReceiverPtr receiver)
{
RegisterReceiverToType(pkgType, receiver);
}
template<typename T>
T* SHEventManager::BroadcastEvent(T data, SHEventIdentifier eventType)
{
SHEventDataPtr ptr = new std::byte[sizeof(data)];
std::memcpy(ptr, &data, sizeof(data));
CatchEvent(
{
eventType,
ptr,
handleCounter++
}
);
return reinterpret_cast<T*>(ptr);
}
/****************************************************************************
* \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.
****************************************************************************/
void SHEventManager::RegisterReceiverToType(
SHEventIdentifier pkgType, ReceiverPtr receiver)
{
if (packageReceiverRegistry.contains(pkgType))
{
packageReceiverRegistry[pkgType].emplace_back(receiver);
}
else
{
packageReceiverRegistry.emplace(pkgType, std::vector{ receiver });
}
}
/****************************************************************************
* \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.
****************************************************************************/
void SHEventManager::Broadcast(SHEvent const& event)
{
ResponseVec& receivers{ packageReceiverRegistry[event.type] };
for (auto& receiver : receivers)
{
receiver->Receive(event);
}
//auto& funcs{ ackageReceiverRegistry[event.GetType()] };
//for (auto func : funcs)
//{
// func(event.GetData());
//}
}
}

View File

@ -0,0 +1,116 @@
/******************************************************************************
* \file SHEventManager.h
* \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 "SHEvent.h"
#include "SHEventReceiver.h"
#include <unordered_map>
#include <functional>
/******************************************************************************
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);
Headers required: SHEventManager.h
On Receiver side:
1. Create a function with the signature:
SHEventHandle FunctionName(SHEvent);
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 void*
properly.
Headers required: SHEventManager.h, SHEventReceiver.h
If you have any questions/suggestions for improvement lmk.
******************************************************************************/
namespace SHADE
{
using ResponseFunction = std::function<SHEventHandle(SHEvent)>;
using ReceiverPtr = std::shared_ptr<SHEventReceiver>;
using ResponseVec = std::vector<ReceiverPtr>;
using StaticResponseVec = std::vector<ResponseFunction>;
using EventManagerListener = std::function<void(SHEvent)>;
class SHEventManager
{
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(SHEvent);
/****************************************************************************
* \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, ReceiverPtr);
template<typename T>
static T* BroadcastEvent(T data, SHEventIdentifier eventType);
private:
// Registry for broadcasters and subscribers
static std::unordered_map<SHEventIdentifier, ResponseVec> packageReceiverRegistry;
static std::unordered_map<SHEventHandle, SHEventDataPtr> dataEventMap;
static SHEventHandle handleCounter;
/****************************************************************************
* \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(SHEvent const&);
/****************************************************************************
* \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, ReceiverPtr);
};
}

View File

@ -0,0 +1,33 @@
#pragma once
#include "SHEvent.h"
namespace SHADE
{
class SHEventReceiver
{
private:
public:
virtual void Receive(SHEvent) = 0;
};
template<typename T>
class SHEventReceiverSpec : public SHEventReceiver
{
private:
T* object;
SHEventHandle(T::*callback)(SHEvent);
public:
SHEventReceiverSpec(T* obj, void(T::* cb)(SHEventDataPtr))
:SHEventReceiver(), object{ obj }, callback{ cb }
{
}
void Receive(SHEvent evt) override
{
(object->*callback)(evt);
}
};
}

View File

@ -30,5 +30,6 @@
#include <functional> #include <functional>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <cstddef>
#include "SHCommonTypes.h" #include "Common/SHCommonTypes.h"