91 lines
3.0 KiB
C++
91 lines
3.0 KiB
C++
#ifndef CREATURELIB_EVENTHOOK_HPP
|
|
#define CREATURELIB_EVENTHOOK_HPP
|
|
|
|
#include <functional>
|
|
#include <thread>
|
|
#include <vector>
|
|
#include "../../Library/Exceptions/CreatureException.hpp"
|
|
#include "EventData.hpp"
|
|
|
|
namespace CreatureLib::Battling {
|
|
/// The Event Hook class allows users to write consumers for the battle events, for example to write User Interfaces
|
|
/// for it.
|
|
class EventHook {
|
|
public:
|
|
typedef std::function<void(const CreatureLib::Battling::EventData*)> EventHookFunc;
|
|
|
|
private:
|
|
std::vector<EventHookFunc> _listeners;
|
|
size_t _offset;
|
|
size_t _capacity;
|
|
uint8_t* _memory = nullptr;
|
|
std::thread* _currentThread = nullptr;
|
|
|
|
static constexpr size_t initialSize = 2048;
|
|
static constexpr size_t stepSize = 1024;
|
|
|
|
public:
|
|
EventHook() : _offset(0), _capacity(2048) {
|
|
auto ptr = malloc(_capacity);
|
|
if (ptr == nullptr) {
|
|
THROW_CREATURE("Out of memory.");
|
|
}
|
|
_memory = static_cast<uint8_t*>(ptr);
|
|
}
|
|
EventHook(const EventHook&) = delete;
|
|
EventHook& operator=(const EventHook&) = delete;
|
|
|
|
~EventHook() {
|
|
free(_memory);
|
|
if (_currentThread != nullptr && _currentThread->joinable()) {
|
|
_currentThread->join();
|
|
delete _currentThread;
|
|
_currentThread = nullptr;
|
|
}
|
|
}
|
|
|
|
size_t GetPosition() const noexcept { return _offset; }
|
|
size_t GetCapacity() const noexcept { return _capacity; }
|
|
|
|
template <class T, class... parameters> void Trigger(parameters... args) {
|
|
if (_listeners.size() == 0)
|
|
return;
|
|
if (_currentThread != nullptr && _currentThread->joinable()) {
|
|
_currentThread->join();
|
|
delete _currentThread;
|
|
_currentThread = nullptr;
|
|
}
|
|
if (_offset + sizeof(T) >= _capacity) {
|
|
_capacity += stepSize;
|
|
auto newPtr = realloc(_memory, _capacity);
|
|
if (newPtr == nullptr) {
|
|
THROW_CREATURE("Out of memory.");
|
|
}
|
|
_memory = static_cast<uint8_t*>(newPtr);
|
|
}
|
|
uint8_t* ptr = _memory + _offset;
|
|
T* event = new (ptr) T(args...);
|
|
_offset += sizeof(T);
|
|
_currentThread = new std::thread(&EventHook::RunListeners, this, event);
|
|
}
|
|
|
|
void RegisterListener(const EventHookFunc& func) { _listeners.push_back(func); }
|
|
|
|
void FinishListening() {
|
|
if (_currentThread != nullptr && _currentThread->joinable()) {
|
|
_currentThread->join();
|
|
delete _currentThread;
|
|
_currentThread = nullptr;
|
|
}
|
|
}
|
|
|
|
private:
|
|
void RunListeners(EventData* event) {
|
|
for (auto listener : _listeners) {
|
|
try_creature(listener(event), "Exception in event listener");
|
|
}
|
|
}
|
|
};
|
|
}
|
|
#endif // CREATURELIB_EVENTHOOK_HPP
|