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