Support clearing event listeners
This commit is contained in:
parent
180af9d404
commit
a6b87fbe7f
@ -43,7 +43,7 @@ namespace game
|
||||
listener.is_volatile = false;
|
||||
listener.callback = callback;
|
||||
|
||||
context->get_event_handler()->add_event_listener(listener);
|
||||
return context->get_event_handler()->add_event_listener(listener);
|
||||
}), "onNotify");
|
||||
|
||||
chai->add(chaiscript::fun([context](const std::string& event,
|
||||
@ -57,7 +57,7 @@ namespace game
|
||||
listener.is_volatile = is_volatile;
|
||||
listener.callback = callback;
|
||||
|
||||
context->get_event_handler()->add_event_listener(listener);
|
||||
return context->get_event_handler()->add_event_listener(listener);
|
||||
}), "onNotify");
|
||||
|
||||
// Notification
|
||||
|
@ -32,7 +32,7 @@ namespace game
|
||||
}
|
||||
}
|
||||
|
||||
void entity::on_notify(const std::string& event,
|
||||
event_listener_handle entity::on_notify(const std::string& event,
|
||||
const std::function<void(const std::vector<chaiscript::Boxed_Value>&)>&
|
||||
callback,
|
||||
const bool is_volatile)
|
||||
@ -44,7 +44,7 @@ namespace game
|
||||
listener.entity_id = this->entity_id_;
|
||||
listener.is_volatile = is_volatile;
|
||||
|
||||
this->context_->get_event_handler()->add_event_listener(listener);
|
||||
return this->context_->get_event_handler()->add_event_listener(listener);
|
||||
}
|
||||
|
||||
unsigned int entity::get_entity_id() const
|
||||
|
@ -6,6 +6,7 @@ namespace game
|
||||
namespace scripting
|
||||
{
|
||||
class context;
|
||||
class event_listener_handle;
|
||||
|
||||
class entity final
|
||||
{
|
||||
@ -15,7 +16,7 @@ namespace game
|
||||
entity(context* context, unsigned int entity_id);
|
||||
~entity();
|
||||
|
||||
void on_notify(const std::string& event,
|
||||
event_listener_handle on_notify(const std::string& event,
|
||||
const std::function<void(const std::vector<chaiscript::Boxed_Value>&)>& callback,
|
||||
bool is_volatile) const;
|
||||
|
||||
|
@ -7,11 +7,21 @@ namespace game
|
||||
{
|
||||
event_handler::event_handler(context* context) : context_(context)
|
||||
{
|
||||
}
|
||||
const auto chai = this->context_->get_chai();
|
||||
|
||||
void event_handler::run_frame()
|
||||
{
|
||||
chai->add(chaiscript::user_type<event_listener_handle>(), "event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle()>(), "event_listener_handle");
|
||||
chai->add(chaiscript::constructor<event_listener_handle(const event_listener_handle&)>(), "event_listener_handle");
|
||||
|
||||
chai->add(chaiscript::fun([](event_listener_handle& lhs, const event_listener_handle& rhs) -> event_listener_handle&
|
||||
{
|
||||
return lhs = rhs;
|
||||
}), "=");
|
||||
|
||||
chai->add(chaiscript::fun([this](const event_listener_handle& handle)
|
||||
{
|
||||
this->remove(handle);
|
||||
}), "clear");
|
||||
}
|
||||
|
||||
void event_handler::dispatch(event* event)
|
||||
@ -37,7 +47,7 @@ namespace game
|
||||
void event_handler::dispatch_to_specific_listeners(event* event,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments)
|
||||
{
|
||||
for (auto listener = this->event_listeners_.begin(); listener.is_valid(); ++listener)
|
||||
for (const auto& listener : this->event_listeners_)
|
||||
{
|
||||
if (listener->event == event->name && listener->entity_id == event->entity_id)
|
||||
{
|
||||
@ -54,7 +64,7 @@ namespace game
|
||||
void event_handler::dispatch_to_generic_listeners(event* event,
|
||||
const std::vector<chaiscript::Boxed_Value>& arguments)
|
||||
{
|
||||
for (auto listener = this->generic_event_listeners_.begin(); listener.is_valid(); ++listener)
|
||||
for (const auto& listener : this->generic_event_listeners_)
|
||||
{
|
||||
if (listener->event == event->name)
|
||||
{
|
||||
@ -68,14 +78,39 @@ namespace game
|
||||
}
|
||||
}
|
||||
|
||||
void event_handler::add_event_listener(const event_listener& listener)
|
||||
event_listener_handle event_handler::add_event_listener(event_listener listener)
|
||||
{
|
||||
listener.id = ++this->current_listener_id_;
|
||||
this->event_listeners_.add(listener);
|
||||
return { listener.id };
|
||||
}
|
||||
|
||||
void event_handler::add_event_listener(const generic_event_listener& listener)
|
||||
event_listener_handle event_handler::add_event_listener(generic_event_listener listener)
|
||||
{
|
||||
listener.id = ++this->current_listener_id_;
|
||||
this->generic_event_listeners_.add(listener);
|
||||
return { listener.id };
|
||||
}
|
||||
|
||||
void event_handler::remove(const event_listener_handle& handle)
|
||||
{
|
||||
for (const auto task : this->event_listeners_)
|
||||
{
|
||||
if (task->id == handle.id)
|
||||
{
|
||||
this->event_listeners_.remove(task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto task : this->generic_event_listeners_)
|
||||
{
|
||||
if (task->id == handle.id)
|
||||
{
|
||||
this->generic_event_listeners_.remove(task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "utils/chain.hpp"
|
||||
#include "utils/concurrent_list.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "event.hpp"
|
||||
|
||||
@ -9,7 +9,13 @@ namespace game
|
||||
{
|
||||
class context;
|
||||
|
||||
class event_listener final
|
||||
class event_listener_handle
|
||||
{
|
||||
public:
|
||||
unsigned long long id = 0;
|
||||
};
|
||||
|
||||
class event_listener final : public event_listener_handle
|
||||
{
|
||||
public:
|
||||
std::string event = {};
|
||||
@ -18,7 +24,7 @@ namespace game
|
||||
bool is_volatile = false;
|
||||
};
|
||||
|
||||
class generic_event_listener final
|
||||
class generic_event_listener final : public event_listener_handle
|
||||
{
|
||||
public:
|
||||
std::string event = {};
|
||||
@ -31,20 +37,22 @@ namespace game
|
||||
public:
|
||||
explicit event_handler(context* context);
|
||||
|
||||
void run_frame();
|
||||
void dispatch(event* event);
|
||||
|
||||
void add_event_listener(const event_listener& listener);
|
||||
void add_event_listener(const generic_event_listener& listener);
|
||||
event_listener_handle add_event_listener(event_listener listener);
|
||||
event_listener_handle add_event_listener(generic_event_listener listener);
|
||||
|
||||
private:
|
||||
context* context_;
|
||||
std::atomic_int64_t current_listener_id_ = 0;
|
||||
|
||||
utils::concurrent_list<event_listener> event_listeners_;
|
||||
utils::concurrent_list<generic_event_listener> generic_event_listeners_;
|
||||
|
||||
void dispatch_to_specific_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments);
|
||||
void dispatch_to_generic_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments);
|
||||
|
||||
utils::chain<event_listener> event_listeners_;
|
||||
utils::chain<generic_event_listener> generic_event_listeners_;
|
||||
void remove(const event_listener_handle& handle);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ namespace game
|
||||
|
||||
void scheduler::run_frame()
|
||||
{
|
||||
for (auto task = this->tasks_.begin(); task.is_valid(); ++task)
|
||||
for (const auto& task : this->tasks_)
|
||||
{
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if ((now - task->last_execution) > task->delay)
|
||||
@ -79,7 +79,7 @@ namespace game
|
||||
|
||||
void scheduler::remove(const task_handle& handle)
|
||||
{
|
||||
for (auto task = this->tasks_.begin(); task.is_valid(); ++task)
|
||||
for (const auto task : this->tasks_)
|
||||
{
|
||||
if(task->id == handle.id)
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "utils/chain.hpp"
|
||||
#include "utils/concurrent_list.hpp"
|
||||
|
||||
namespace game
|
||||
{
|
||||
@ -32,7 +32,7 @@ namespace game
|
||||
private:
|
||||
context* context_;
|
||||
|
||||
utils::chain<task> tasks_;
|
||||
utils::concurrent_list<task> tasks_;
|
||||
std::atomic_int64_t current_task_id_ = 0;
|
||||
|
||||
task_handle add(const std::function<void()>& callback, long long milliseconds, bool is_volatile);
|
||||
|
@ -6,19 +6,19 @@
|
||||
|
||||
std::mutex scheduler::mutex_;
|
||||
std::queue<std::pair<std::string, int>> scheduler::errors_;
|
||||
std::vector<std::function<void()>> scheduler::callbacks_;
|
||||
std::vector<std::function<void()>> scheduler::single_callbacks_;
|
||||
utils::concurrent_list<std::function<void()>> scheduler::callbacks_;
|
||||
utils::concurrent_list<std::function<void()>> scheduler::single_callbacks_;
|
||||
|
||||
void scheduler::on_frame(const std::function<void()>& callback)
|
||||
{
|
||||
std::lock_guard _(mutex_);
|
||||
callbacks_.push_back(callback);
|
||||
callbacks_.add(callback);
|
||||
}
|
||||
|
||||
void scheduler::once(const std::function<void()>& callback)
|
||||
{
|
||||
std::lock_guard _(mutex_);
|
||||
single_callbacks_.push_back(callback);
|
||||
single_callbacks_.add(callback);
|
||||
}
|
||||
|
||||
void scheduler::error(const std::string& message, int level)
|
||||
@ -39,24 +39,14 @@ __declspec(naked) void scheduler::execute()
|
||||
|
||||
void scheduler::execute_safe()
|
||||
{
|
||||
std::vector<std::function<void()>> callbacks_copy;
|
||||
std::vector<std::function<void()>> single_callbacks_copy;
|
||||
|
||||
for (const auto& callback : callbacks_)
|
||||
{
|
||||
std::lock_guard _(mutex_);
|
||||
callbacks_copy = callbacks_;
|
||||
single_callbacks_copy = single_callbacks_;
|
||||
single_callbacks_.clear();
|
||||
(*callback)();
|
||||
}
|
||||
|
||||
for (const auto& callback : callbacks_copy)
|
||||
for (const auto& callback : single_callbacks_)
|
||||
{
|
||||
callback();
|
||||
}
|
||||
|
||||
for (const auto& callback : single_callbacks_copy)
|
||||
{
|
||||
callback();
|
||||
(*callback)();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/concurrent_list.hpp"
|
||||
|
||||
class scheduler final : public module
|
||||
{
|
||||
@ -15,8 +16,8 @@ public:
|
||||
private:
|
||||
static std::mutex mutex_;
|
||||
static std::queue<std::pair<std::string, int>> errors_;
|
||||
static std::vector<std::function<void()>> callbacks_;
|
||||
static std::vector<std::function<void()>> single_callbacks_;
|
||||
static utils::concurrent_list<std::function<void()>> callbacks_;
|
||||
static utils::concurrent_list<std::function<void()>> single_callbacks_;
|
||||
|
||||
static void execute_safe();
|
||||
static void execute_error();
|
||||
|
@ -3,30 +3,26 @@
|
||||
namespace utils
|
||||
{
|
||||
template <typename T>
|
||||
class chain final
|
||||
class concurrent_list final
|
||||
{
|
||||
public:
|
||||
class entry final
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<T> object_;
|
||||
std::shared_ptr<entry> next_;
|
||||
|
||||
public:
|
||||
|
||||
bool has_next()
|
||||
{
|
||||
return (this->next_.use_count() > 0);
|
||||
return this->next_.operator bool();
|
||||
}
|
||||
|
||||
bool is_valid()
|
||||
{
|
||||
return (this->object_.use_count() > 0);
|
||||
return this->object_.operator bool();
|
||||
}
|
||||
|
||||
void set(T object)
|
||||
|
||||
void set(const std::shared_ptr<T>& object)
|
||||
{
|
||||
this->object_ = std::make_shared<T>();
|
||||
*this->object_.get() = object;
|
||||
this->object_ = object;
|
||||
}
|
||||
|
||||
std::shared_ptr<T> get()
|
||||
@ -38,7 +34,7 @@ namespace utils
|
||||
{
|
||||
if (this->has_next())
|
||||
{
|
||||
return *(this->next_.get());
|
||||
return *this->next_;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -56,67 +52,85 @@ namespace utils
|
||||
this->next_ = entry;
|
||||
}
|
||||
|
||||
T *operator->()
|
||||
T* operator->()
|
||||
{
|
||||
return (this->object_.get());
|
||||
return this->object_.get();
|
||||
}
|
||||
|
||||
entry& operator++ ()
|
||||
std::shared_ptr<T> operator*()
|
||||
{
|
||||
return this->object_;
|
||||
}
|
||||
|
||||
explicit operator bool()
|
||||
{
|
||||
return this->is_valid();
|
||||
}
|
||||
|
||||
bool operator==(const entry& other)
|
||||
{
|
||||
return this->object_.get() == other.object_.get();
|
||||
}
|
||||
|
||||
bool operator!=(const entry& other)
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
entry& operator++()
|
||||
{
|
||||
*this = this->get_next();
|
||||
return *this;
|
||||
}
|
||||
|
||||
entry operator++ (int)
|
||||
entry operator++(int)
|
||||
{
|
||||
entry result = *this;
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<T> object_;
|
||||
std::shared_ptr<entry> next_;
|
||||
};
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
entry object_;
|
||||
|
||||
public:
|
||||
void add(const T& object)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
|
||||
if (!this->empty())
|
||||
{
|
||||
// Create new chain entry
|
||||
std::shared_ptr<entry> current_object = std::make_shared<entry>();
|
||||
*current_object.get() = this->object_;
|
||||
current_object->set(this->object_.get());
|
||||
|
||||
// Add it to the chain
|
||||
this->object_ = entry();
|
||||
this->object_.set_next_entry(current_object);
|
||||
}
|
||||
|
||||
this->object_.set(object);
|
||||
const auto obj_ptr = std::make_shared<T>(object);
|
||||
this->object_.set(obj_ptr);
|
||||
}
|
||||
|
||||
void remove(std::shared_ptr<T> object)
|
||||
void remove(const std::shared_ptr<T>& object)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
|
||||
if (!this->empty())
|
||||
{
|
||||
if (this->object_.get().get() == object.get())
|
||||
if (this->object_.get() == object)
|
||||
{
|
||||
this->object_ = this->object_.get_next();
|
||||
}
|
||||
else if(this->object_.has_next())
|
||||
else if (this->object_.has_next())
|
||||
{
|
||||
for (auto entry = this->object_; entry.is_valid(); ++entry)
|
||||
{
|
||||
auto next = entry.get_next();
|
||||
|
||||
if (next.is_valid() && next.get().get() == object.get())
|
||||
if (next.is_valid() && next.get() == object)
|
||||
{
|
||||
*entry.get_next_entry().get() = next.get_next();
|
||||
entry.set_next_entry(next.get_next_entry());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -133,7 +147,7 @@ namespace utils
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return !this->object_.is_valid();
|
||||
return !this->object_;
|
||||
}
|
||||
|
||||
entry begin()
|
||||
@ -141,9 +155,18 @@ namespace utils
|
||||
return this->object_;
|
||||
}
|
||||
|
||||
entry end()
|
||||
{
|
||||
return entry();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
this->object_ = entry();
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
entry object_;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user