Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Create Event System (EPI-47/EPI-49/EPI-50/EPI-51/EPI-52/EPI-54) #7

Merged
merged 16 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ target_sources(StellarForgeCommon
${CMAKE_CURRENT_SOURCE_DIR}/IError.hpp
${CMAKE_CURRENT_SOURCE_DIR}/UUID.hpp
${CMAKE_CURRENT_SOURCE_DIR}/UUIDException.hpp
${CMAKE_CURRENT_SOURCE_DIR}/event/EventData.hpp
${CMAKE_CURRENT_SOURCE_DIR}/event/EventSystem.hpp
${CMAKE_CURRENT_SOURCE_DIR}/managers/ObjectManager.hpp
${CMAKE_CURRENT_SOURCE_DIR}/managers/SceneManager.hpp
${CMAKE_CURRENT_SOURCE_DIR}/managers/ManagerException.hpp
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/UUID.cpp
${CMAKE_CURRENT_SOURCE_DIR}/UUIDException.cpp
${CMAKE_CURRENT_SOURCE_DIR}/event/EventSystem.cpp
${CMAKE_CURRENT_SOURCE_DIR}/managers/ObjectManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/managers/SceneManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/managers/ManagerException.cpp
Expand Down
35 changes: 35 additions & 0 deletions src/common/event/EventData.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
** EPITECH PROJECT, 2024
** Stellar-Forge
** File description:
** EventData
*/

#ifndef EVENTDATA_HPP
#define EVENTDATA_HPP

#include <functional>

/**
* @brief Structure to hold event data
* @param name std::string, name of the event
* @param timestamp time_t, timestamp of the event
* @param data void *, data of the event (can be anything)
* @note This structure is used to pass data to the event consumers
*/
struct EventData
{
std::string name;
time_t timestamp;
void* data;
};

/**
* @brief Event consumer function type
*
* @param EventData_t * structure containing the event data
* @note This function type is used to define the event consumers
*/
using EventConsumer = std::function<void (const EventData&)>;

#endif // EVENTDATA_HPP
100 changes: 100 additions & 0 deletions src/common/event/EventSystem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
** EPITECH PROJECT, 2024
** Stellar-Forge
** File description:
** EventSystem
*/

#include "EventSystem.hpp"

EventSystem::EventSystem(): _listeners({})
{
_event_system = this;
}

EventSystem::~EventSystem()
{
for (auto& [_, listenerVector] : this->_listeners)
{
listenerVector.clear();
}
this->_listeners.clear();
}

UUID EventSystem::registerListener(const std::string& name, const EventConsumer& listener)
{
auto uuid = UUID();
uuid.generateUuid();

if (this->_listeners.find(name) == this->_listeners.end())
{
this->_listeners[name] = std::vector<std::pair<UUID, EventConsumer>>();
}
this->_listeners[name].emplace_back(uuid, listener);
return uuid;
}

bool EventSystem::unregisterListener(const UUID& uuid)
{
for (auto& [key, listenersVector] : this->_listeners)
{
for (int i = 0; i < listenersVector.size(); i++)
{
if (listenersVector[i].first == uuid)
{
listenersVector.erase(listenersVector.begin() + i);
if (listenersVector.empty())
{
this->_listeners.erase(key);
}
return true;
}
}
}
return false;
}

bool EventSystem::triggerEvents(const std::string& eventName, void* data)
{
auto const eventData = EventData{eventName, std::time(nullptr), data};
bool handled = false;

if (this->_listeners.find(eventName) != this->_listeners.end())
{
handled = this->_triggerEventFromEventName(eventName, eventData) || handled;
}
for (auto& [key, _] : this->_listeners)
{
std::size_t const found = key.find('*');
if (found != std::string::npos)
{
std::string const name = key.substr(0, found);
if (eventName.find(name) == 0)
{
handled = this->_triggerEventFromEventName(key, eventData) || handled;
}
}
}
return handled;
}

bool EventSystem::_triggerEventFromEventName(const std::string& eventName, const EventData& eventData)
{
bool handled = false;

for (auto& [_, callback] : this->_listeners[eventName])
{
callback(eventData);
handled = true;
}
return handled;
}

EventSystem* EventSystem::getInstance()
{
if (_event_system == nullptr)
{
return nullptr;
}
return _event_system;
}
124 changes: 124 additions & 0 deletions src/common/event/EventSystem.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
** EPITECH PROJECT, 2024
** Stellar-Forge
** File description:
** EventSystem
*/

#ifndef EVENTSYSTEM_HPP
#define EVENTSYSTEM_HPP

#include "../UUID.hpp"
#include "EventData.hpp"

/**
* @brief Event System class
* @details This class is used to manage events and event listeners
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
class EventSystem
{
public:
/**
* @brief Default constructor
* @details This constructor initializes the event system
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
EventSystem();

/**
* @brief Default destructor
* @details This destructor clears the event system
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
~EventSystem();

/**
* @brief Register a listener for an event
* @details This function registers a listener for an event
* @param name std::string, the name of the event
* @param listener EventConsumer, the listener to register
* @return UUID, the UUID of the listener
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
UUID registerListener(const std::string& name, const EventConsumer& listener);

/**
* @brief Unregister a listener
* @details This function unregisters a listener
* @param uuid UUID, the UUID of the listener to unregister
* @return bool, true if the listener was unregistered,
* false if the listener was not found
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
bool unregisterListener(const UUID& uuid);

/**
* @brief Trigger an event
* @details This function triggers an event
* @param eventName std::string, the name of the event to trigger
* @param data void*, the data to pass to the listeners
* @return bool, true if at least one listener was found,
* false if no listener was found
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
bool triggerEvents(const std::string& eventName, void* data = nullptr);

/**
* @brief Get the instance of the event system
* @details This function returns an instance of the event system
* @return EventSystem*, the instance of the event system
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
static EventSystem* getInstance();

private:
/**
* @brief Trigger an event from the event name
* @details This function triggers an event from the event name
* @param eventName std::string, the name of the event to trigger
* @param eventData EventData, the data to pass to the listeners
* @return bool, true if at least one listener was found,
* false if no listener was found
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
bool _triggerEventFromEventName(const std::string& eventName, const EventData& eventData);

/**
* @brief Listeners
* @details This unordered map contains the listeners
* the key is the name of the event and the value is a vector of pairs
* that contains the UUID of the listener and the listener itself
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
std::unordered_map<std::string, std::vector<std::pair<UUID, EventConsumer>>> _listeners;

/**
* @brief Event manager
* @details This static pointer contains the event manager
* @version 0.1.0
* @since 0.1.0
* @author Marius PAIN
*/
static EventSystem* _event_system;
};

#endif // EVENTSYSTEM_HPP